summaryrefslogtreecommitdiff
path: root/alsactl
diff options
context:
space:
mode:
authorAbramo Bagnara <abramo@alsa-project.org>2000-08-25 14:34:26 +0000
committerAbramo Bagnara <abramo@alsa-project.org>2000-08-25 14:34:26 +0000
commit8c4e1aa76980d0248a0e90cc6510dc0836ab2843 (patch)
tree1c75ad5b8f12cc1d9164158c3727a8181855938d /alsactl
parent6add1cdfb51f283f1e58ba3fe8c8805d49384686 (diff)
downloadalsa-utils-8c4e1aa76980d0248a0e90cc6510dc0836ab2843.tar.gz
Rewritten alsactl
Diffstat (limited to 'alsactl')
-rw-r--r--alsactl/Makefile.am8
-rw-r--r--alsactl/alsactl.c997
-rw-r--r--alsactl/alsactl.h70
-rw-r--r--alsactl/alsactl_lexer.l114
-rw-r--r--alsactl/alsactl_parser.y319
-rw-r--r--alsactl/merge.c170
-rw-r--r--alsactl/setup.c530
7 files changed, 928 insertions, 1280 deletions
diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am
index 3df5067..b0d2fa5 100644
--- a/alsactl/Makefile.am
+++ b/alsactl/Makefile.am
@@ -1,10 +1,4 @@
sbin_PROGRAMS=alsactl
-noinst_HEADERS=alsactl.h
man_MANS=alsactl.1
-alsactl_SOURCES=alsactl.c alsactl_parser.y setup.c merge.c alsactl_lexer.l
-YFLAGS=-d
-
-# lexer / parser debug
-#CFLAGS=-pipe -g -DYYDEBUG
-#LFLAGS=-d
+alsactl_SOURCES=alsactl.c
diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c
index cdd81f7..2f8b69e 100644
--- a/alsactl/alsactl.c
+++ b/alsactl/alsactl.c
@@ -1,6 +1,7 @@
/*
* Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1997 by Perex, APS, University of South Bohemia
+ * Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
+ * Jaroslav Kysela <perex@suse.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -19,54 +20,887 @@
*
*/
-#include "alsactl.h"
#include "aconfig.h"
#include "version.h"
#include <getopt.h>
#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/asoundlib.h>
-#define HELPID_HELP 1000
-#define HELPID_FILE 1001
-#define HELPID_DEBUG 1002
-#define HELPID_VERSION 1003
-
-extern int yyparse(void);
-extern int linecount;
-extern FILE *yyin;
-extern int yydebug;
+#define SYS_ASOUNDRC "/etc/asound.conf"
int debugflag = 0;
-char cfgfile[512] = ALSACTL_FILE;
+char *command;
-void error(const char *fmt,...)
-{
- va_list va;
-
- va_start(va, fmt);
- fprintf(stderr, "alsactl: ");
- vfprintf(stderr, fmt, va);
- fprintf(stderr, "\n");
- va_end(va);
-}
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define error(...) do {\
+ fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ putc('\n', stderr); \
+} while (0)
+#else
+#define error(args...) do {\
+ fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
+ fprintf(stderr, ##args); \
+ putc('\n', stderr); \
+} while (0)
+#endif
static void help(void)
{
printf("Usage: alsactl <options> command\n");
printf("\nAvailable options:\n");
printf(" -h,--help this help\n");
- printf(" -f,--file # configuration file (default " ALSACTL_FILE ")\n");
+ printf(" -f,--file # configuration file (default " SYS_ASOUNDRC ")\n");
printf(" -d,--debug debug mode\n");
printf(" -v,--version print version of this program\n");
printf("\nAvailable commands:\n");
- printf(" store <card #> store current driver setup for one or each soundcards\n");
+ printf(" store <card #> save current driver setup for one or each soundcards\n");
printf(" to configuration file\n");
- printf(" restore <card #> restore current driver setup for one or each soundcards\n");
- printf(" from configuration file\n");
+ printf(" restore<card #> load current driver setup for one or each soundcards\n");
+ printf(" from configuration file\n");
+}
+
+char *id_str(snd_control_id_t *id)
+{
+ static char str[128];
+ assert(id);
+ sprintf(str, "%i,%i,%i,%s,%i", id->iface, id->device, id->subdevice, id->name, id->index);
+ return str;
+}
+
+char *num_str(long n)
+{
+ static char str[32];
+ sprintf(str, "%ld", n);
+ return str;
+}
+
+static int snd_config_integer_add(snd_config_t *father, char *id, long integer)
+{
+ int err;
+ snd_config_t *leaf;
+ err = snd_config_integer_make(&leaf, id);
+ if (err < 0)
+ return err;
+ err = snd_config_add(father, leaf);
+ if (err < 0) {
+ snd_config_delete(leaf);
+ return err;
+ }
+ err = snd_config_integer_set(leaf, integer);
+ if (err < 0) {
+ snd_config_delete(leaf);
+ return err;
+ }
+ return 0;
+}
+
+static int snd_config_string_add(snd_config_t *father, char *id, char *string)
+{
+ int err;
+ snd_config_t *leaf;
+ err = snd_config_string_make(&leaf, id);
+ if (err < 0)
+ return err;
+ err = snd_config_add(father, leaf);
+ if (err < 0) {
+ snd_config_delete(leaf);
+ return err;
+ }
+ err = snd_config_string_set(leaf, string);
+ if (err < 0) {
+ snd_config_delete(leaf);
+ return err;
+ }
+ return 0;
+}
+
+static int snd_config_compound_add(snd_config_t *father, char *id, int join,
+ snd_config_t **node)
+{
+ int err;
+ snd_config_t *leaf;
+ err = snd_config_compound_make(&leaf, id, join);
+ if (err < 0)
+ return err;
+ err = snd_config_add(father, leaf);
+ if (err < 0) {
+ snd_config_delete(leaf);
+ return err;
+ }
+ *node = leaf;
+ return 0;
+}
+
+static int get_control(snd_ctl_t *handle, snd_control_id_t *id, snd_config_t *top)
+{
+ snd_control_t ctl;
+ snd_control_info_t info;
+ snd_config_t *control, *comment, *item, *value;
+ char *s;
+ char buf[256];
+ int idx, err;
+
+ memset(&info, 0, sizeof(info));
+ info.id = *id;
+ err = snd_ctl_cinfo(handle, &info);
+ if (err < 0) {
+ error("Cannot read control info '%s': %s", id_str(id), snd_strerror(err));
+ return err;
+ }
+
+ if (!(info.access & SND_CONTROL_ACCESS_READ))
+ return 0;
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.id = info.id;
+ err = snd_ctl_cread(handle, &ctl);
+ if (err < 0) {
+ error("Cannot read control '%s': %s", id_str(id), snd_strerror(err));
+ return err;
+ }
+
+ err = snd_config_compound_add(top, num_str(info.id.numid), 0, &control);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ return err;
+ }
+ err = snd_config_compound_add(control, "comment", 1, &comment);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ return err;
+ }
+
+ buf[0] = '\0';
+ buf[1] = '\0';
+ if (info.access & SND_CONTROL_ACCESS_READ)
+ strcat(buf, " read");
+ if (info.access & SND_CONTROL_ACCESS_WRITE)
+ strcat(buf, " write");
+ if (info.access & SND_CONTROL_ACCESS_INACTIVE)
+ strcat(buf, " inactive");
+ err = snd_config_string_add(comment, "access", buf + 1);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ s = "bool";
+ break;
+ case SND_CONTROL_TYPE_INTEGER:
+ s = "integer";
+ break;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ s = "enumerated";
+ break;
+ case SND_CONTROL_TYPE_BYTES:
+ s = "bytes";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ err = snd_config_string_add(comment, "type", s);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ if (info.value.integer.min != 0 || info.value.integer.max != 1 ||
+ info.value.integer.step != 0)
+ error("Bad boolean control '%s'", id_str(id));
+
+ break;
+ case SND_CONTROL_TYPE_INTEGER:
+ sprintf(buf, "%li - %li (step %li)", info.value.integer.min, info.value.integer.max, info.value.integer.step);
+ err = snd_config_string_add(comment, "range", buf);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ break;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ err = snd_config_compound_add(comment, "item", 1, &item);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ return err;
+ }
+ for (idx = 0; idx < info.value.enumerated.items; idx++) {
+ info.value.enumerated.item = idx;
+ err = snd_ctl_cinfo(handle, &info);
+ if (err < 0) {
+ error("snd_ctl_info: %s", snd_strerror(err));
+ return err;
+ }
+ err = snd_config_string_add(item, num_str(idx), info.value.enumerated.name);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ switch (info.id.iface) {
+ case SND_CONTROL_IFACE_CARD:
+ s = "global";
+ break;
+ case SND_CONTROL_IFACE_HWDEP:
+ s = "hwdep";
+ break;
+ case SND_CONTROL_IFACE_MIXER:
+ s = "mixer";
+ break;
+ case SND_CONTROL_IFACE_PCM:
+ s = "pcm";
+ break;
+ case SND_CONTROL_IFACE_RAWMIDI:
+ s = "rawmidi";
+ break;
+ case SND_CONTROL_IFACE_TIMER:
+ s = "timer";
+ break;
+ case SND_CONTROL_IFACE_SEQUENCER:
+ s = "sequencer";
+ break;
+ default:
+ s = num_str(info.id.iface);
+ break;
+ }
+ err = snd_config_string_add(control, "iface", s);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ if (info.id.device != 0) {
+ err = snd_config_integer_add(control, "device", info.id.device);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ if (info.id.subdevice != 0) {
+ err = snd_config_integer_add(control, "subdevice", info.id.subdevice);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ err = snd_config_string_add(control, "name", info.id.name);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ if (info.id.index != 0) {
+ err = snd_config_integer_add(control, "index", info.id.index);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+
+ if (info.type == SND_CONTROL_TYPE_BYTES) {
+ char buf[info.values_count * 2 + 1];
+ char *p = buf;
+ char *hex = "0123456789abcdef";
+ for (idx = 0; idx < info.values_count; idx++) {
+ int v = ctl.value.bytes.data[idx];
+ *p++ = hex[v >> 4];
+ *p++ = hex[v & 0x0f];
+ }
+ *p = '\0';
+ err = snd_config_string_add(control, "value", buf);
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ return 0;
+ }
+
+ if (info.values_count == 1) {
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ err = snd_config_string_add(control, "value", ctl.value.integer.value[0] ? "true" : "false");
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ return 0;
+ case SND_CONTROL_TYPE_INTEGER:
+ err = snd_config_integer_add(control, "value", ctl.value.integer.value[0]);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ return 0;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ {
+ unsigned int v = ctl.value.integer.value[0];
+ snd_config_t *c;
+ err = snd_config_search(item, num_str(v), &c);
+ if (err == 0) {
+ err = snd_config_string_get(c, &s);
+ assert(err == 0);
+ err = snd_config_string_add(control, "value", s);
+ } else {
+ err = snd_config_integer_add(control, "value", v);
+ }
+ if (err < 0)
+ error("snd_config add: %s", snd_strerror(err));
+ return 0;
+ }
+ default:
+ error("Unknown control type: %d\n", info.type);
+ return -EINVAL;
+ }
+ }
+
+ err = snd_config_compound_add(control, "value", 1, &value);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ return err;
+ }
+
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ for (idx = 0; idx < info.values_count; idx++) {
+ err = snd_config_string_add(value, num_str(idx), ctl.value.integer.value[idx] ? "true" : "false");
+ if (err < 0) {
+ error("snd_config_string_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ break;
+ case SND_CONTROL_TYPE_INTEGER:
+ for (idx = 0; idx < info.values_count; idx++) {
+ err = snd_config_integer_add(value, num_str(idx), ctl.value.integer.value[idx]);
+ if (err < 0) {
+ error("snd_config_integer_add: %s", snd_strerror(err));
+ return err;
+ }
+ }
+ break;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ for (idx = 0; idx < info.values_count; idx++) {
+ unsigned int v = ctl.value.integer.value[idx];
+ snd_config_t *c;
+ err = snd_config_search(item, num_str(v), &c);
+ if (err == 0) {
+ err = snd_config_string_get(c, &s);
+ assert(err == 0);
+ err = snd_config_string_add(value, num_str(idx), s);
+ } else {
+ err = snd_config_integer_add(value, num_str(idx), v);
+ }
+ if (err < 0)
+ error("snd_config add: %s", snd_strerror(err));
+ return err;
+ }
+ break;
+ default:
+ error("Unknown control type: %d\n", info.type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_controls(int cardno, snd_config_t *top)
+{
+ snd_ctl_t *handle;
+ snd_ctl_hw_info_t info;
+ snd_config_t *state, *card, *control;
+ snd_control_list_t list;
+ int idx, err;
+
+ err = snd_ctl_open(&handle, cardno);
+ if (err < 0) {
+ error("snd_ctl_open error: %s", snd_strerror(err));
+ return err;
+ }
+ err = snd_ctl_hw_info(handle, &info);
+ if (err < 0) {
+ error("snd_ctl_hw_info error: %s", snd_strerror(err));
+ goto _close;
+ }
+ err = snd_config_search(top, "state", &state);
+ if (err == 0 &&
+ snd_config_type(state) != SND_CONFIG_TYPE_COMPOUND) {
+ error("config state node is not a compound");
+ err = -EINVAL;
+ goto _close;
+ }
+ if (err < 0) {
+ err = snd_config_compound_add(top, "state", 1, &state);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ goto _close;
+ }
+ }
+ err = snd_config_search(state, info.id, &card);
+ if (err == 0 &&
+ snd_config_type(state) != SND_CONFIG_TYPE_COMPOUND) {
+ error("config state.%s node is not a compound", info.id);
+ err = -EINVAL;
+ goto _close;
+ }
+ if (err < 0) {
+ err = snd_config_compound_add(state, info.id, 0, &card);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ goto _close;
+ }
+ }
+ err = snd_config_search(card, "control", &control);
+ if (err == 0) {
+ err = snd_config_delete(control);
+ if (err < 0) {
+ error("snd_config_delete: %s", snd_strerror(err));
+ goto _close;
+ }
+ }
+ err = snd_config_compound_add(card, "control", 1, &control);
+ if (err < 0) {
+ error("snd_config_compound_add: %s", snd_strerror(err));
+ goto _close;
+ }
+ memset(&list, 0, sizeof(list));
+ err = snd_ctl_clist(handle, &list);
+ if (err < 0) {
+ error("Cannot determine controls: %s", snd_strerror(err));
+ goto _close;
+ }
+ if (list.controls <= 0) {
+ err = 0;
+ goto _close;
+ }
+ list.controls_request = list.controls;
+ list.controls_offset = list.controls_count = 0;
+ list.pids = malloc(sizeof(snd_control_id_t) * list.controls_request);
+ if (!list.pids) {
+ error("No enough memory...");
+ goto _close;
+ }
+ if ((err = snd_ctl_clist(handle, &list)) < 0) {
+ error("Cannot determine controls (2): %s", snd_strerror(err));
+ goto _free;
+ }
+ for (idx = 0; idx < list.controls_count; ++idx) {
+ err = get_control(handle, &list.pids[idx], control);
+ if (err < 0)
+ goto _free;
+ }
+
+ err = 0;
+ _free:
+ free(list.pids);
+ _close:
+ snd_ctl_close(handle);
+ return err;
+}
+
+
+static int config_iface(snd_config_t *n)
+{
+ static struct {
+ int val;
+ char *str;
+ } v[] = {
+ { SND_CONTROL_IFACE_CARD, "card" },
+ { SND_CONTROL_IFACE_HWDEP, "hwdep" },
+ { SND_CONTROL_IFACE_MIXER, "mixer" },
+ { SND_CONTROL_IFACE_PCM, "pcm" },
+ { SND_CONTROL_IFACE_RAWMIDI, "rawmidi" },
+ { SND_CONTROL_IFACE_TIMER, "timer" },
+ { SND_CONTROL_IFACE_SEQUENCER, "sequencer" }
+ };
+ long idx;
+ char *str;
+ switch (snd_config_type(n)) {
+ case SND_CONFIG_TYPE_INTEGER:
+ snd_config_integer_get(n, &idx);
+ return idx;
+ case SND_CONFIG_TYPE_STRING:
+ snd_config_string_get(n, &str);
+ break;
+ default:
+ return -1;
+ }
+ for (idx = 0; idx < sizeof(v) / sizeof(v[0]); ++idx) {
+ if (strcmp(v[idx].str, str) == 0)
+ return idx;
+ }
+ return -1;
+}
+
+static int config_bool(snd_config_t *n)
+{
+ char *str;
+ long val;
+ switch (snd_config_type(n)) {
+ case SND_CONFIG_TYPE_INTEGER:
+ snd_config_integer_get(n, &val);
+ if (val < 0 || val > 1)
+ return -1;
+ return val;
+ case SND_CONFIG_TYPE_STRING:
+ snd_config_string_get(n, &str);
+ break;
+ default:
+ return -1;
+ }
+ if (strcmp(str, "on") || strcmp(str, "true"))
+ return 1;
+ if (strcmp(str, "off") || strcmp(str, "false"))
+ return 0;
+ return -1;
+}
+
+static int config_enumerated(snd_config_t *n, snd_ctl_t *handle,
+ snd_control_info_t *info)
+{
+ char *str;
+ long val;
+ int idx;
+ switch (snd_config_type(n)) {
+ case SND_CONFIG_TYPE_INTEGER:
+ snd_config_integer_get(n, &val);
+ return val;
+ case SND_CONFIG_TYPE_STRING:
+ snd_config_string_get(n, &str);
+ break;
+ default:
+ return -1;
+ }
+ for (idx = 0; idx < info->value.enumerated.items; idx++) {
+ int err;
+ info->value.enumerated.item = idx;
+ err = snd_ctl_cinfo(handle, info);
+ if (err < 0) {
+ error("snd_ctl_info: %s", snd_strerror(err));
+ return err;
+ }
+ if (strcmp(str, info->value.enumerated.name) == 0)
+ return idx;
+ }
+ return -1;
+}
+
+static int set_control(snd_ctl_t *handle, snd_config_t *control)
+{
+ snd_control_t ctl;
+ snd_control_info_t info;
+ snd_config_iterator_t i;
+ int numid;
+ long iface = -1;
+ long device = -1;
+ long subdevice = -1;
+ char *name = NULL;
+ long index = -1;
+ snd_config_t *value = NULL;
+ long val;
+ int idx, err;
+ char *set;
+ if (snd_config_type(control) != SND_CONFIG_TYPE_COMPOUND) {
+ error("control is not a compound");
+ return -EINVAL;
+ }
+ numid = atoi(snd_config_id(control));
+ snd_config_foreach(i, control) {
+ snd_config_t *n = snd_config_entry(i);
+ char *fld = snd_config_id(n);
+ if (strcmp(fld, "comment") == 0)
+ continue;
+ if (strcmp(fld, "iface") == 0) {
+ iface = config_iface(n);
+ if (iface < 0) {
+ error("control.%d.%s is invalid", numid, fld);
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (strcmp(fld, "device") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_INTEGER) {
+ error("control.%d.%s is invalid", numid, fld);
+ return -EINVAL;
+ }
+ snd_config_integer_get(n, &device);
+ continue;
+ }
+ if (strcmp(fld, "subdevice") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_INTEGER) {
+ error("control.%d.%s is invalid", numid, fld);
+ return -EINVAL;
+ }
+ snd_config_integer_get(n, &subdevice);
+ continue;
+ }
+ if (strcmp(fld, "name") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_STRING) {
+ error("control.%d.%s is invalid", numid, fld);
+ return -EINVAL;
+ }
+ snd_config_string_get(n, &name);
+ continue;
+ }
+ if (strcmp(fld, "index") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_INTEGER) {
+ error("control.%d.%s is invalid", numid, fld);
+ return -EINVAL;
+ }
+ snd_config_integer_get(n, &index);
+ continue;
+ }
+ if (strcmp(fld, "value") == 0) {
+ value = n;
+ continue;
+ }
+ error("unknown control.%d.%s field", numid, fld);
+ }
+ if (!value) {
+ error("missing control.%d.value", numid);
+ return -EINVAL;
+ }
+ if (device < 0)
+ device = 0;
+ if (subdevice < 0)
+ subdevice = 0;
+ if (index < 0)
+ index = 0;
+ memset(&info, 0, sizeof(info));
+ info.id.numid = numid;
+ err = snd_ctl_cinfo(handle, &info);
+ if (err < 0) {
+ if (iface >= 0 && name) {
+ info.id.numid = 0;
+ info.id.iface = iface;
+ info.id.device = device;
+ info.id.subdevice = subdevice;
+ strncmp(info.id.name, name, sizeof(info.id.name));
+ info.id.index = index;
+ err = snd_ctl_cinfo(handle, &info);
+ }
+ }
+ if (err < 0) {
+ error("failed to obtain info for control #%d (%s)", numid, snd_strerror(err));
+ return -ENOENT;
+ }
+ if (info.id.numid != numid)
+ error("warning: numid mismatch (%d/%d) for control #%d", numid, info.id.numid, numid);
+ if (info.id.iface != iface)
+ error("warning: iface mismatch (%ld/%d) for control #%d", iface, info.id.iface, numid);
+ if (info.id.device != device)
+ error("warning: device mismatch (%ld/%d) for control #%d", device, info.id.device, numid);
+ if (info.id.subdevice != subdevice)
+ error("warning: subdevice mismatch (%ld/%d) for control #%d", subdevice, info.id.subdevice, numid);
+ if (strcmp(info.id.name, name))
+ error("warning: name mismatch (%s/%s) for control #%d", name, info.id.name, numid);
+ if (info.id.index != index)
+ error("warning: index mismatch (%ld/%d) for control #%d", index, info.id.index, numid);
+
+ if (!(info.access & SND_CONTROL_ACCESS_WRITE))
+ return 0;
+
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.id = info.id;
+
+ if (info.values_count == 1) {
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ val = config_bool(value);
+ if (val >= 0) {
+ ctl.value.integer.value[0] = val;
+ goto _ok;
+ }
+ break;
+ case SND_CONTROL_TYPE_INTEGER:
+ err = snd_config_integer_get(value, &val);
+ if (err == 0) {
+ ctl.value.integer.value[0] = val;
+ goto _ok;
+ }
+ break;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ val = config_enumerated(value, handle, &info);
+ if (val >= 0) {
+ ctl.value.enumerated.item[0] = val;
+ goto _ok;
+ }
+ break;
+ default:
+ error("Unknow control type: %d", info.type);
+ return -EINVAL;
+ }
+ }
+ if (info.type == SND_CONTROL_TYPE_BYTES) {
+ char *buf;
+ err = snd_config_string_get(value, &buf);
+ if (err > 0) {
+ int c1 = 0;
+ int len = strlen(buf);
+ int idx = 0;
+ if (info.values_count * 2 != len) {
+ error("bad control.%d.value contents\n", numid);
+ return -EINVAL;
+ }
+ while (*buf) {
+ int c = *buf;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c <= 'a' && c <= 'f')
+ c = c - 'a' + 10;
+ else if (c <= 'A' && c <= 'F')
+ c = c - 'A' + 10;
+ else {
+ error("bad control.%d.value contents\n", numid);
+ return -EINVAL;
+ }
+ idx++;
+ if (idx % 2 == 0)
+ ctl.value.bytes.data[idx / 2] = c1 << 4 | c;
+ else
+ c1 = c;
+ }
+ goto _ok;
+ }
+ }
+ if (snd_config_type(value) != SND_CONFIG_TYPE_COMPOUND) {
+ error("bad control.%d.value type", numid);
+ return -EINVAL;
+ }
+
+ set = alloca(info.values_count);
+ memset(set, 0, info.values_count);
+ snd_config_foreach(i, value) {
+ snd_config_t *n = snd_config_entry(i);
+ idx = atoi(snd_config_id(n));
+ if (idx < 0 || idx >= info.values_count ||
+ set[idx]) {
+ error("bad control.%d.value index", numid);
+ return -EINVAL;
+ }
+ switch (info.type) {
+ case SND_CONTROL_TYPE_BOOLEAN:
+ val = config_bool(n);
+ if (val < 0) {
+ error("bad control.%d.value.%d content", numid, idx);
+ return -EINVAL;
+ }
+ ctl.value.integer.value[idx] = val;
+ break;
+ case SND_CONTROL_TYPE_INTEGER:
+ err = snd_config_integer_get(n, &val);
+ if (err < 0) {
+ error("bad control.%d.value.%d content", numid, idx);
+ return -EINVAL;
+ }
+ ctl.value.integer.value[idx] = val;
+ break;
+ case SND_CONTROL_TYPE_ENUMERATED:
+ val = config_enumerated(n, handle, &info);
+ if (val < 0) {
+ error("bad control.%d.value.%d content", numid, idx);
+ return -EINVAL;
+ }
+ ctl.value.enumerated.item[idx] = val;
+ break;
+ case SND_CONTROL_TYPE_BYTES:
+ err = snd_config_integer_get(n, &val);
+ if (err < 0 || val < 0 || val > 255) {
+ error("bad control.%d.value.%d content", numid, idx);
+ return -EINVAL;
+ }
+ ctl.value.integer.value[idx] = val;
+ break;
+ default:
+ break;
+ }
+ set[idx] = 1;
+ }
+ for (idx = 0; idx < info.values_count; ++idx) {
+ if (!set[idx]) {
+ error("control.%d.value.%d is not specified", numid, idx);
+ return -EINVAL;
+ }
+ }
+
+ _ok:
+ err = snd_ctl_cwrite(handle, &ctl);
+ if (err < 0) {
+ error("Cannot write control '%s': %s", id_str(&ctl.id), snd_strerror(err));
+ return err;
+ }
+ return 0;
+}
+
+static int set_controls(int card, snd_config_t *top)
+{
+ snd_ctl_t *handle;
+ snd_ctl_hw_info_t info;
+ snd_config_t *control;
+ snd_config_iterator_t i;
+ int err;
+
+ err = snd_ctl_open(&handle, card);
+ if (err < 0) {
+ error("snd_ctl_open error: %s", snd_strerror(err));
+ return err;
+ }
+ err = snd_ctl_hw_info(handle, &info);
+ if (err < 0) {
+ error("snd_ctl_hw_info error: %s", snd_strerror(err));
+ goto _close;
+ }
+ err = snd_config_searchv(top, &control, "state", info.id, "control", 0);
+ if (err < 0) {
+ err = 0;
+ fprintf(stderr, "No state is present for card %s\n", info.id);
+ goto _close;
+ }
+ if (snd_config_type(control) != SND_CONFIG_TYPE_COMPOUND) {
+ error("state.%s.control is not a compound\n", info.id);
+ return -EINVAL;
+ }
+ snd_config_foreach(i, control) {
+ snd_config_t *n = snd_config_entry(i);
+ err = set_control(handle, n);
+ if (err < 0)
+ goto _close;
+ }
+
+ _close:
+ snd_ctl_close(handle);
+ return err;
}
-static int store_setup(const char *cardname)
+
+static int save_state(char *file, const char *cardname)
{
int err;
+ snd_config_t *config;
+ FILE *fp;
+
+ err = snd_config_top(&config);
+ if (err < 0) {
+ error("snd_config_top error: %s", snd_strerror(err));
+ return err;
+ }
+ fp = fopen(file, "r");
+ if (fp) {
+ err = snd_config_load(config, fp);
+ fclose(fp);
+ if (err < 0) {
+ error("snd_config_load error: %s", snd_strerror(err));
+ return err;
+ }
+ }
if (!cardname) {
unsigned int card_mask, idx;
@@ -76,62 +910,88 @@ static int store_setup(const char *cardname)
error("No soundcards found...");
return 1;
}
- soundcard_setup_init();
for (idx = 0; idx < 32; idx++) {
if (card_mask & (1 << idx)) { /* find each installed soundcards */
- if ((err = soundcard_setup_collect_controls(idx))) {
- soundcard_setup_done();
+ if ((err = get_controls(idx, config))) {
return err;
}
}
}
- err = soundcard_setup_write(cfgfile, -1);
- soundcard_setup_done();
} else {
int cardno;
- cardno = snd_card_name(cardname);
+ cardno = snd_card_get_index(cardname);
if (cardno < 0) {
error("Cannot find soundcard '%s'...", cardname);
return 1;
}
- if ((err = soundcard_setup_collect_controls(cardno))) {
- soundcard_setup_done();
+ if ((err = get_controls(cardno, config))) {
return err;
}
- err = soundcard_setup_write(cfgfile, cardno);
- soundcard_setup_done();
}
- return err;
+
+ fp = fopen(file, "w");
+ if (!fp) {
+ error("Cannot open %s for writing", file);
+ return -errno;
+ }
+ err = snd_config_save(config, fp);
+ fclose(fp);
+ if (err < 0)
+ error("snd_config_save: %s", snd_strerror(err));
+ return 0;
}
-static int restore_setup(const char *cardname)
+
+static int load_state(char *file, const char *cardname)
{
- int err, cardno = -1;
+ int err;
+ snd_config_t *config;
+ FILE *fp;
- if (cardname) {
- cardno = snd_card_name(cardname);
+ err = snd_config_top(&config);
+ if (err < 0) {
+ error("snd_config_top error: %s", snd_strerror(err));
+ return err;
+ }
+ fp = fopen(file, "r");
+ if (fp) {
+ err = snd_config_load(config, fp);
+ fclose(fp);
+ if (err < 0) {
+ error("snd_config_load error: %s", snd_strerror(err));
+ return err;
+ }
+ }
+
+ if (!cardname) {
+ unsigned int card_mask, idx;
+
+ card_mask = snd_cards_mask();
+ if (!card_mask) {
+ error("No soundcards found...");
+ return 1;
+ }
+ for (idx = 0; idx < 32; idx++) {
+ if (card_mask & (1 << idx)) { /* find each installed soundcards */
+ if ((err = set_controls(idx, config))) {
+ return err;
+ }
+ }
+ }
+ } else {
+ int cardno;
+
+ cardno = snd_card_get_index(cardname);
if (cardno < 0) {
error("Cannot find soundcard '%s'...", cardname);
return 1;
}
+ if ((err = set_controls(cardno, config))) {
+ return err;
+ }
}
- if ((err = soundcard_setup_load(cfgfile, 0)))
- return err;
- if ((err = soundcard_setup_collect_controls(cardno))) {
- soundcard_setup_done();
- return err;
- }
- if ((err = soundcard_setup_merge_controls(cardno))) {
- soundcard_setup_done();
- return err;
- }
- if ((err = soundcard_setup_process_controls(cardno))) {
- soundcard_setup_done();
- return err;
- }
- soundcard_setup_done();
- return err;
+ return 0;
}
int main(int argc, char *argv[])
@@ -139,13 +999,15 @@ int main(int argc, char *argv[])
int morehelp;
struct option long_option[] =
{
- {"help", 0, NULL, HELPID_HELP},
- {"file", 1, NULL, HELPID_FILE},
- {"debug", 0, NULL, HELPID_DEBUG},
- {"version", 0, NULL, HELPID_VERSION},
+ {"help", 0, NULL, 'h'},
+ {"file", 1, NULL, 'f'},
+ {"debug", 0, NULL, 'd'},
+ {"version", 0, NULL, 'v'},
{NULL, 0, NULL, 0},
};
+ char *cfgfile = SYS_ASOUNDRC;
+ command = argv[0];
morehelp = 0;
while (1) {
int c;
@@ -154,20 +1016,15 @@ int main(int argc, char *argv[])
break;
switch (c) {
case 'h':
- case HELPID_HELP:
morehelp++;
break;
case 'f':
- case HELPID_FILE:
- strncpy(cfgfile, optarg, sizeof(cfgfile) - 1);
- cfgfile[sizeof(cfgfile) - 1] = 0;
+ cfgfile = optarg;
break;
case 'd':
- case HELPID_DEBUG:
debugflag = 1;
break;
case 'v':
- case HELPID_VERSION:
printf("alsactl version " SND_UTIL_VERSION_STR "\n");
return 1;
default:
@@ -184,10 +1041,10 @@ int main(int argc, char *argv[])
return 0;
}
if (!strcmp(argv[optind], "store")) {
- return store_setup(argc - optind > 1 ? argv[optind + 1] : NULL) ?
+ return save_state(cfgfile, argc - optind > 1 ? argv[optind + 1] : NULL) ?
1 : 0;
} else if (!strcmp(argv[optind], "restore")) {
- return restore_setup(argc - optind > 1 ? argv[optind + 1] : NULL) ?
+ return load_state(cfgfile, argc - optind > 1 ? argv[optind + 1] : NULL) ?
1 : 0;
} else {
fprintf(stderr, "alsactl: Unknown command '%s'...\n", argv[optind]);
diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h
deleted file mode 100644
index 89df00a..0000000
--- a/alsactl/alsactl.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1997 by Perex, APS, University of South Bohemia
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/asoundlib.h>
-
-#define ALSACTL_FILE "/etc/asound.conf"
-
-#define LEFT 1
-#define RIGHT 2
-
-#define OUTPUT 0
-#define INPUT 1
-
-extern int debugflag;
-
-extern void error(const char *fmt,...);
-
-struct ctl_control {
- int change;
- snd_control_type_t type;
- snd_control_info_t info;
- snd_control_t c;
- struct ctl_control *next;
-};
-
-struct ctl {
- snd_ctl_hw_info_t hwinfo;
- struct ctl_control *controls;
-};
-
-struct soundcard {
- int no; /* card number */
- struct ctl control;
- struct soundcard *next;
-};
-
-extern struct soundcard *soundcards;
-extern struct soundcard *rsoundcards; /* read soundcards */
-
-void soundcard_setup_init(void);
-void soundcard_setup_done(void);
-int soundcard_setup_load(const char *filename, int skip);
-int soundcard_setup_write(const char *filename, int cardno);
-int soundcard_setup_collect_controls(int cardno);
-int soundcard_setup_merge_controls(int cardno);
-int soundcard_setup_process_controls(int cardno);
-
-char *control_id(snd_control_id_t *id);
diff --git a/alsactl/alsactl_lexer.l b/alsactl/alsactl_lexer.l
deleted file mode 100644
index 7253c16..0000000
--- a/alsactl/alsactl_lexer.l
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1998 by Perex, APS, University of South Bohemia
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-%{
-
-#include "alsactl.h"
-
-struct bytearray {
- unsigned char *data;
- size_t datalen;
-};
-
-#include "alsactl_parser.h"
-
-#define YY_NO_UNPUT
-#undef YY_CDECL
-#define YY_CDECL int YY_PROTO(yylex( void ));
-
-int linecount;
-
-%}
-
-%%
-
- /* special characters */
-
-"{"|"}" return yytext[0];
-"("|")" return yytext[0];
-"["|"]" return yytext[0];
-")"[ \t]*"{" return L_DOUBLE1;
-"," return yytext[0];
-"=" return yytext[0];
-
- /* tokens */
-
-soundcard return L_SOUNDCARD;
-control return L_CONTROL;
-
-global return L_GLOBAL;
-hwdep return L_HWDEP;
-mixer return L_MIXER;
-pcm return L_PCM;
-rawmidi return L_RAWMIDI;
-timer return L_TIMER;
-sequencer return L_SEQUENCER;
-
-ident return L_IDENT;
-iface return L_IFACE;
-name return L_NAME;
-device return L_DEVICE;
-subdevice return L_SUBDEVICE;
-index return L_INDEX;
-
-bool return L_BOOL;
-int return L_INT;
-enum return L_ENUM;
-byte return L_BYTE;
-
- /* boolean */
-
-false|off|no return L_FALSE;
-true|on|yes return L_TRUE;
-
- /* integers */
-
-[0-9]+ { yylval.i_value = strtol(yytext, (char **)NULL, 10); return L_INTEGER; }
-0x[0-9a-f]+ { yylval.i_value = strtol(yytext, (char **)NULL, 0); return L_INTEGER; }
-
- /* strings */
-
-\"[^\"]*\" { yytext[strlen(yytext) - 1] = 0;
- yylval.s_value = strdup(&yytext[1]);
- return L_STRING; }
-\'[^\']*\' { yytext[strlen(yytext) - 1] = 0;
- yylval.s_value = strdup(&yytext[1]);
- return L_STRING; }
-[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(yytext);
- return L_STRING; }
-$[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(getenv(&yytext[1]));
- return L_STRING; }
-
- /* comments & whitespaces */
-
-[#\;][^\n]*\n { linecount++; }
-[ \t]+ ;
-\n { linecount++; }
-. fprintf( stderr, "alsactl: discarding char '%c' - line %i\n", yytext[0], linecount + 1 );
-
-%%
-
-#ifndef yywrap
-int yywrap(void) /* do this avoid to do -lfl */
-{
- return 1;
-}
-#endif
diff --git a/alsactl/alsactl_parser.y b/alsactl/alsactl_parser.y
deleted file mode 100644
index 8eef8ff..0000000
--- a/alsactl/alsactl_parser.y
+++ /dev/null
@@ -1,319 +0,0 @@
-%{
-
-/*
- * Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1998 by Perex, APS, University of South Bohemia
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "alsactl.h"
-#include <stdarg.h>
-
- /* insgus_lexer.c */
-
-int yylex( void );
-
-extern char cfgfile[];
-extern int linecount;
-extern FILE *yyin;
-
- /* structure for byte arrays */
-
-struct bytearray {
- unsigned char *data;
- size_t datalen;
-};
-
- /* local functions */
-
-static void yyerror(char *, ...);
-
-static void build_soundcard(char *name);
-static void build_control_begin(void);
-static void build_control_end(void);
-static void set_control_iface(int iface);
-static void set_control_device(int dev);
-static void set_control_subdevice(int subdev);
-static void set_control_name(char *name);
-static void set_control_index(int idx);
-static void set_control_type(snd_control_type_t type);
-static void set_control_boolean(int val);
-static void set_control_integer(long val);
-
- /* local variables */
-
-static struct soundcard *Xsoundcard = NULL;
-static struct ctl_control *Xcontrol = NULL;
-static int Xposition = 0;
-static snd_control_type_t Xtype = SND_CONTROL_TYPE_NONE;
-
-%}
-
-%start lines
-
-%union {
- int b_value;
- long i_value;
- char *s_value;
- struct bytearray a_value;
- };
-
-%token <b_value> L_TRUE L_FALSE
-%token <i_value> L_INTEGER
-%token <s_value> L_STRING
-%token <a_value> L_BYTEARRAY
-
- /* types */
-%token L_INTEGER L_STRING
- /* boolean */
-%token L_FALSE L_TRUE
- /* misc */
-%token L_DOUBLE1
- /* other keywords */
-%token L_SOUNDCARD L_CONTROL L_RAWDATA
-%token L_GLOBAL L_HWDEP L_MIXER L_PCM L_RAWMIDI L_TIMER L_SEQUENCER
-%token L_IDENT L_IFACE L_NAME L_DEVICE L_SUBDEVICE L_INDEX
-%token L_BOOL L_INT L_ENUM L_BYTE
-
-%type <b_value> boolean
-%type <i_value> integer iface
-%type <s_value> string
-%type <a_value> rawdata
-
-%%
-
-lines : line
- | lines line
- ;
-
-line : L_SOUNDCARD '(' string { build_soundcard($3); }
- L_DOUBLE1 soundcards '}' { build_soundcard(NULL); }
- | error { yyerror("unknown keyword in top level"); }
- ;
-
-soundcards :
- | soundcards soundcard
- ;
-
-soundcard : L_CONTROL '(' L_IDENT '=' { build_control_begin(); }
- '{' ctlids '}' ',' controls ')' { build_control_end(); }
- | error { yyerror("an unknown keyword in the soundcard{} level"); }
- ;
-
-ctlids : ctlid
- | ctlids ',' ctlid
- ;
-
-ctlid : L_IFACE '=' iface { set_control_iface($3); }
- | L_DEVICE '=' integer { set_control_device($3); }
- | L_SUBDEVICE '=' integer { set_control_subdevice($3); }
- | L_NAME '=' string { set_control_name($3); }
- | L_INDEX '=' integer { set_control_index($3); }
- | error { yyerror("an unknown keyword in the control ID level"); }
- ;
-
-controls : control
- ;
-
-control : L_BOOL '=' { set_control_type(SND_CONTROL_TYPE_BOOLEAN); } '{' datas '}'
- | L_INT '=' { set_control_type(SND_CONTROL_TYPE_INTEGER); } '{' datas '}'
- | L_ENUM '=' { set_control_type(SND_CONTROL_TYPE_ENUMERATED); } '{' datas '}'
- | L_BYTE '=' { set_control_type(SND_CONTROL_TYPE_BYTES); } '{' datas '}'
- | error { yyerror( "an unknown keyword in the control() data parameter" ); }
- ;
-
-datas : data
- | datas ',' data
- ;
-
-data : boolean { set_control_boolean($1); }
- | integer { set_control_integer($1); }
- | error { yyerror( "an unknown keyword in the control() data argument" ); }
- ;
-
-iface : L_INTEGER { $$ = $1; }
- | L_GLOBAL { $$ = SND_CONTROL_IFACE_CARD; }
- | L_HWDEP { $$ = SND_CONTROL_IFACE_HWDEP; }
- | L_MIXER { $$ = SND_CONTROL_IFACE_MIXER; }
- | L_PCM { $$ = SND_CONTROL_IFACE_PCM; }
- | L_RAWMIDI { $$ = SND_CONTROL_IFACE_RAWMIDI; }
- | L_TIMER { $$ = SND_CONTROL_IFACE_TIMER; }
- | L_SEQUENCER { $$ = SND_CONTROL_IFACE_SEQUENCER; }
- | error { yyerror( "an unknown keyword in the interface field"); }
- ;
-
-boolean : L_TRUE { $$ = 1; }
- | L_FALSE { $$ = 0; }
- ;
-
-integer : L_INTEGER { $$ = $1; }
- ;
-
-string : L_STRING { $$ = $1; }
- ;
-
-rawdata : L_RAWDATA '(' L_BYTEARRAY ')' { $$ = $3; }
- | L_RAWDATA error { yyerror( "malformed rawdata value" ); }
- ;
-
-%%
-
-static void yyerror(char *string,...)
-{
- char errstr[1024];
-
- va_list vars;
- va_start(vars, string);
- vsprintf(errstr, string, vars);
- va_end(vars);
- error("Error in configuration file '%s' (line %i): %s", cfgfile, linecount + 1, errstr);
-
- exit(1);
-}
-
-static void error_nomem(void)
-{
- yyerror("No enough memory...\n");
-}
-
-static void build_soundcard(char *name)
-{
- struct soundcard *soundcard;
-
- if (!name) {
- Xsoundcard = NULL;
- return;
- }
- Xsoundcard = (struct soundcard *)malloc(sizeof(struct soundcard));
- if (!Xsoundcard) {
- free(name);
- error_nomem();
- return;
- }
- bzero(Xsoundcard, sizeof(*Xsoundcard));
- for (soundcard = rsoundcards; soundcard && soundcard->next; soundcard = soundcard->next);
- if (soundcard) {
- soundcard->next = Xsoundcard;
- } else {
- rsoundcards = Xsoundcard;
- }
- strncpy(Xsoundcard->control.hwinfo.id, name, sizeof(Xsoundcard->control.hwinfo.id));
- free(name);
-}
-
-static void build_control_begin(void)
-{
- struct ctl_control **first;
- struct ctl_control *ctl;
-
- first = &Xsoundcard->control.controls;
- Xcontrol = (struct ctl_control *)malloc(sizeof(struct ctl_control));
- if (!Xcontrol) {
- error_nomem();
- return;
- }
- Xposition = 0;
- Xtype = SND_CONTROL_TYPE_NONE;
- bzero(Xcontrol, sizeof(*Xcontrol));
- for (ctl = *first; ctl && ctl->next; ctl = ctl->next);
- if (ctl) {
- ctl->next = Xcontrol;
- } else {
- *first = Xcontrol;
- }
-}
-
-static void build_control_end(void)
-{
- Xcontrol = NULL;
-}
-
-static void set_control_iface(int iface)
-{
- Xcontrol->c.id.iface = iface;
-}
-
-static void set_control_device(int dev)
-{
- Xcontrol->c.id.device = dev;
-}
-
-static void set_control_subdevice(int subdev)
-{
- Xcontrol->c.id.subdevice = subdev;
-}
-
-static void set_control_name(char *name)
-{
- if (name == NULL)
- return;
- strncpy(Xcontrol->c.id.name, name, sizeof(Xcontrol->c.id.name));
- free(name);
-}
-
-static void set_control_index(int idx)
-{
- Xcontrol->c.id.index = idx;
-}
-
-static void set_control_type(snd_control_type_t type)
-{
- Xcontrol->type = Xtype = type;
-}
-
-static void set_control_boolean(int val)
-{
- if (Xposition >= 512)
- yyerror("Array overflow.");
- switch (Xtype) {
- case SND_CONTROL_TYPE_BOOLEAN:
- Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
- break;
- case SND_CONTROL_TYPE_INTEGER:
- Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
- break;
- case SND_CONTROL_TYPE_ENUMERATED:
- Xcontrol->c.value.enumerated.item[Xposition++] = val ? 1 : 0;
- break;
- case SND_CONTROL_TYPE_BYTES:
- Xcontrol->c.value.bytes.data[Xposition++] = val ? 1 : 0;
- break;
- default: break;
- }
-}
-
-static void set_control_integer(long val)
-{
- if (Xposition >= 512)
- yyerror("Array overflow.");
- switch (Xtype) {
- case SND_CONTROL_TYPE_BOOLEAN:
- Xcontrol->c.value.integer.value[Xposition++] = val ? 1 : 0;
- break;
- case SND_CONTROL_TYPE_INTEGER:
- Xcontrol->c.value.integer.value[Xposition++] = val;
- break;
- case SND_CONTROL_TYPE_ENUMERATED:
- Xcontrol->c.value.enumerated.item[Xposition++] = (unsigned int)val;
- break;
- case SND_CONTROL_TYPE_BYTES:
- Xcontrol->c.value.bytes.data[Xposition++] = (unsigned char)val;
- break;
- default: break;
- }
-}
diff --git a/alsactl/merge.c b/alsactl/merge.c
deleted file mode 100644
index 46d87f1..0000000
--- a/alsactl/merge.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "alsactl.h"
-
-static int merge_one_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
-{
- int idx;
-
- if (!(cctl->info.access & SND_CONTROL_ACCESS_WRITE))
- return 0;
- switch (cctl->info.type) {
- case SND_CONTROL_TYPE_BOOLEAN:
- if (uctl->type != SND_CONTROL_TYPE_BOOLEAN) {
- error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
- return 1;
- }
- for (idx = 0; idx < cctl->info.values_count; idx++) {
- if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
- cctl->change = 1;
- cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
- }
- }
- break;
- case SND_CONTROL_TYPE_INTEGER:
- if (uctl->type != SND_CONTROL_TYPE_INTEGER) {
- error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
- return 1;
- }
- for (idx = 0; idx < cctl->info.values_count; idx++) {
- if (cctl->info.value.integer.min > uctl->c.value.integer.value[idx] ||
- cctl->info.value.integer.max < uctl->c.value.integer.value[idx]) {
- error("The value %li for the control '%s' is out of range %i-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.integer.min, cctl->info.value.integer.max);
- return 1;
- }
- if (cctl->c.value.integer.value[idx] != uctl->c.value.integer.value[idx]) {
- cctl->change = 1;
- cctl->c.value.integer.value[idx] = uctl->c.value.integer.value[idx];
- }
- }
- break;
- case SND_CONTROL_TYPE_ENUMERATED:
- if (uctl->type != SND_CONTROL_TYPE_ENUMERATED) {
- error("A wrong type %i for the control '%s'. The type integer is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
- return 1;
- }
- for (idx = 0; idx < cctl->info.values_count; idx++) {
- if (cctl->info.value.enumerated.items <= uctl->c.value.enumerated.item[idx]) {
- error("The value %u for the control '%s' is out of range 0-%i.", uctl->c.value.integer.value[idx], control_id(&uctl->c.id), cctl->info.value.enumerated.items-1);
- return 1;
- }
- if (cctl->c.value.enumerated.item[idx] != uctl->c.value.enumerated.item[idx]) {
- cctl->change = 1;
- cctl->c.value.enumerated.item[idx] = uctl->c.value.enumerated.item[idx];
- }
- }
- break;
- case SND_CONTROL_TYPE_BYTES:
- if (uctl->type != SND_CONTROL_TYPE_BYTES) {
- error("A wrong type %i for the control %s. The type 'bytes' is expected. Skipping...", uctl->type, control_id(&uctl->c.id));
- return 1;
- }
- if (memcmp(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count)) {
- cctl->change = 1;
- memcpy(cctl->c.value.bytes.data, uctl->c.value.bytes.data, uctl->info.values_count);
- }
- break;
- default:
- error("The control type %i is not known.", cctl->type);
- }
- return 0;
-}
-
-static int soundcard_setup_merge_control(struct ctl_control *cctl, struct ctl_control *uctl, int cardno)
-{
- struct ctl_control *cctl1;
-
- for ( ; uctl; uctl = uctl->next) {
- for (cctl1 = cctl; cctl1; cctl1 = cctl1->next) {
- if (cctl1->c.id.iface == uctl->c.id.iface &&
- cctl1->c.id.device == uctl->c.id.device &&
- cctl1->c.id.subdevice == uctl->c.id.subdevice &&
- !strncmp(cctl1->c.id.name, uctl->c.id.name, sizeof(cctl1->c.id.name)) &&
- cctl1->c.id.index == uctl->c.id.index) {
- merge_one_control(cctl1, uctl, cardno);
- break;
- }
- }
- if (!cctl1) {
- error("Cannot find the control %s...", control_id(&uctl->c.id));
- }
- }
- return 0;
-}
-
-int soundcard_setup_merge_controls(int cardno)
-{
- struct soundcard *soundcard, *rsoundcard;
-
- for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
- for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
- if (!strncmp(soundcard->control.hwinfo.id, rsoundcard->control.hwinfo.id, sizeof(soundcard->control.hwinfo.id)))
- break;
- }
- if (!soundcard) {
- error("The soundcard '%s' was not found...\n", rsoundcard->control.hwinfo.id);
- continue;
- }
- if (cardno >= 0 && soundcard->no != cardno)
- continue;
- soundcard_setup_merge_control(soundcard->control.controls, rsoundcard->control.controls, soundcard->no);
- }
- return 0;
-}
-
-static int soundcard_open_ctl(snd_ctl_t **ctlhandle, struct soundcard *soundcard)
-{
- int err;
-
- if (*ctlhandle)
- return 0;
- if ((err = snd_ctl_open(ctlhandle, soundcard->no)) < 0) {
- error("Cannot open control interface for soundcard #%i.", soundcard->no + 1);
- return 1;
- }
- return 0;
-}
-
-int soundcard_setup_process_controls(int cardno)
-{
- int err;
- snd_ctl_t *ctlhandle = NULL;
- struct soundcard *soundcard;
- struct ctl_control *ctl;
-
- for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
- if (cardno >= 0 && soundcard->no != cardno)
- continue;
- for (ctl = soundcard->control.controls; ctl; ctl = ctl->next) {
- if (ctl->change)
- if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
- if ((err = snd_ctl_cwrite(ctlhandle, &ctl->c)) < 0)
- error("Control '%s' write error: %s", control_id(&ctl->c.id), snd_strerror(err));
- }
- }
- if (ctlhandle) {
- snd_ctl_close(ctlhandle);
- ctlhandle = NULL;
- }
- }
- return 0;
-}
diff --git a/alsactl/setup.c b/alsactl/setup.c
deleted file mode 100644
index 8385268..0000000
--- a/alsactl/setup.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Advanced Linux Sound Architecture Control Program
- * Copyright (c) 1997 by Perex, APS, University of South Bohemia
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "alsactl.h"
-
-#define SND_INTERFACE_CONTROL 0
-#define SND_INTERFACE_MIXER 1
-#define SND_INTERFACE_PCM 2
-#define SND_INTERFACE_RAWMIDI 3
-
-extern int yyparse(void);
-extern int linecount;
-extern FILE *yyin;
-extern int yydebug;
-struct soundcard *soundcards = NULL;
-struct soundcard *rsoundcards = NULL;
-
-/*
- * misc functions
- */
-
-char *control_id(snd_control_id_t *id)
-{
- static char str[128];
-
- if (!id)
- return "???";
- sprintf(str, "%i,%i,%i,%s,%i", id->iface, id->device, id->subdevice, id->name, id->index);
- return str;
-}
-
-/*
- * free functions
- */
-
-static void soundcard_ctl_control_free(struct ctl_control *first)
-{
- struct ctl_control *next;
-
- while (first) {
- next = first->next;
- free(first);
- first = next;
- }
-}
-
-static void soundcard_free1(struct soundcard *soundcard)
-{
- if (!soundcard)
- return;
- soundcard_ctl_control_free(soundcard->control.controls);
- free(soundcard);
-}
-
-static void soundcard_free(struct soundcard *first)
-{
- struct soundcard *next;
-
- while (first) {
- next = first->next;
- soundcard_free1(first);
- first = next;
- }
-}
-
-static int soundcard_remove(int cardno)
-{
- struct soundcard *first, *prev = NULL, *next;
-
- first = soundcards;
- while (first) {
- next = first->next;
- if (first->no == cardno) {
- soundcard_free1(first);
- if (!prev)
- soundcards = next;
- else
- prev->next = next;
- return 0;
- }
- prev = first;
- first = first->next;
- }
- return -1;
-}
-
-/*
- * exported functions
- */
-
-void soundcard_setup_init(void)
-{
- soundcards = NULL;
-}
-
-void soundcard_setup_done(void)
-{
- soundcard_free(soundcards);
- soundcard_free(rsoundcards);
- soundcards = NULL;
-}
-
-static int determine_controls(void *handle, struct ctl_control **cctl)
-{
- int err, idx;
- snd_control_list_t list;
- snd_control_id_t *item;
- snd_control_t ctl;
- struct ctl_control *prev_control;
- struct ctl_control *new_control;
-
- *cctl = NULL;
- bzero(&list, sizeof(list));
- if ((err = snd_ctl_clist(handle, &list)) < 0) {
- error("Cannot determine controls: %s", snd_strerror(err));
- return 1;
- }
- if (list.controls <= 0)
- return 0;
- list.controls_request = list.controls + 16;
- list.controls_offset = list.controls_count = 0;
- list.pids = malloc(sizeof(snd_control_id_t) * list.controls_request);
- if (!list.pids) {
- error("No enough memory...");
- return 1;
- }
- if ((err = snd_ctl_clist(handle, &list)) < 0) {
- error("Cannot determine controls (2): %s", snd_strerror(err));
- return 1;
- }
- for (idx = 0, prev_control = NULL; idx < list.controls_count; idx++) {
- item = &list.pids[idx];
- bzero(&ctl, sizeof(ctl));
- ctl.id = *item;
- if ((err = snd_ctl_cread(handle, &ctl)) < 0) {
- error("Cannot read control '%s': %s", control_id(item), snd_strerror(err));
- free(list.pids);
- return 1;
- }
- new_control = malloc(sizeof(*new_control));
- if (!new_control) {
- error("No enough memory...");
- free(list.pids);
- return 1;
- }
- bzero(new_control, sizeof(*new_control));
- memcpy(&new_control->c, &ctl, sizeof(new_control->c));
- new_control->info.id = ctl.id;
- if ((err = snd_ctl_cinfo(handle, &new_control->info)) < 0) {
- error("Cannot read control info '%s': %s", control_id(item), snd_strerror(err));
- free(new_control);
- free(list.pids);
- return 1;
- }
- if (*cctl) {
- prev_control->next = new_control;
- prev_control = new_control;
- } else {
- *cctl = prev_control = new_control;
- }
- }
- free(list.pids);
- return 0;
-}
-
-static int soundcard_setup_collect_controls1(int cardno)
-{
- snd_ctl_t *handle;
- struct soundcard *card, *first, *prev;
- int err;
-
- soundcard_remove(cardno);
- if ((err = snd_ctl_open(&handle, cardno)) < 0) {
- error("SND CTL open error: %s", snd_strerror(err));
- return 1;
- }
- /* --- */
- card = (struct soundcard *) malloc(sizeof(struct soundcard));
- if (!card) {
- snd_ctl_close(handle);
- error("malloc error");
- return 1;
- }
- bzero(card, sizeof(struct soundcard));
- card->no = cardno;
- for (first = soundcards, prev = NULL; first; first = first->next) {
- if (first->no > cardno) {
- if (!prev) {
- soundcards = card;
- } else {
- prev->next = card;
- }
- card->next = first;
- break;
- }
- prev = first;
- }
- if (!first) {
- if (!soundcards) {
- soundcards = card;
- } else {
- prev->next = card;
- }
- }
- if ((err = snd_ctl_hw_info(handle, &card->control.hwinfo)) < 0) {
- snd_ctl_close(handle);
- error("SND CTL HW INFO error: %s", snd_strerror(err));
- return 1;
- }
- /* --- */
- if (determine_controls(handle, &card->control.controls)) {
- snd_ctl_close(handle);
- return 1;
- }
- /* --- */
- snd_ctl_close(handle);
- return 0;
-}
-
-int soundcard_setup_collect_controls(int cardno)
-{
- int err;
- unsigned int mask;
-
- if (cardno >= 0) {
- return soundcard_setup_collect_controls1(cardno);
- } else {
- mask = snd_cards_mask();
- for (cardno = 0; cardno < SND_CARDS; cardno++) {
- if (!(mask & (1 << cardno)))
- continue;
- err = soundcard_setup_collect_controls1(cardno);
- if (err)
- return err;
- }
- return 0;
- }
-}
-
-int soundcard_setup_load(const char *cfgfile, int skip)
-{
- extern int yyparse(void);
- extern int linecount;
- extern FILE *yyin;
-#ifdef YYDEBUG
- extern int yydebug;
-#endif
- int xtry;
-
-#ifdef YYDEBUG
- yydebug = 1;
-#endif
- if (debugflag)
- printf("cfgfile = '%s'\n", cfgfile);
- if (skip && access(cfgfile, R_OK))
- return 0;
- if ((yyin = fopen(cfgfile, "r")) == NULL) {
- error("Cannot open configuration file '%s'...", cfgfile);
- return 1;
- }
- linecount = 0;
- xtry = yyparse();
- fclose(yyin);
- if (debugflag)
- printf("Config ok..\n");
- if (xtry)
- error("Ignored error in configuration file '%s'...", cfgfile);
- return 0;
-}
-
-static void soundcard_setup_write_control(FILE * out, const char *space, int card, struct ctl_control *control)
-{
- char *s, v[16];
- int err, idx;
- snd_ctl_t *handle;
- snd_control_info_t info;
-
- memcpy(&info, &control->info, sizeof(info));
- v[0] = '\0';
- switch (info.type) {
- case SND_CONTROL_TYPE_BOOLEAN: s = "bool"; break;
- case SND_CONTROL_TYPE_INTEGER: s = "integer"; break;
- case SND_CONTROL_TYPE_ENUMERATED: s = "enumerated"; break;
- case SND_CONTROL_TYPE_BYTES: s = "bytes"; break;
- default: s = "unknown";
- }
- fprintf(out, "\n%s; The type is '%s'. Access:", space, s);
- if (info.access & SND_CONTROL_ACCESS_READ)
- fprintf(out, " read");
- if (info.access & SND_CONTROL_ACCESS_WRITE)
- fprintf(out, " write");
- if (info.access & SND_CONTROL_ACCESS_INACTIVE)
- fprintf(out, " inactive");
- fprintf(out, ". Count is %i.\n", info.values_count);
- switch (info.type) {
- case SND_CONTROL_TYPE_BOOLEAN:
- if (info.value.integer.min != 0 || info.value.integer.max != 1 ||
- info.value.integer.step != 0)
- error("Wrong control '%s' (boolean)\n", control_id(&info.id));
- break;
- case SND_CONTROL_TYPE_INTEGER:
- fprintf(out, "%s; The range is %li-%li (step %li)\n", space, info.value.integer.min, info.value.integer.max, info.value.integer.step);
- break;
- case SND_CONTROL_TYPE_ENUMERATED:
- if ((err = snd_ctl_open(&handle, card)) >= 0) {
- for (idx = 0; idx < info.value.enumerated.items; idx++) {
- info.value.enumerated.item = idx;
- if (snd_ctl_cinfo(handle, &info) >= 0)
- fprintf(out, "%s; Item #%i - %s\n", space, idx, info.value.enumerated.name);
- }
- snd_ctl_close(handle);
- }
- break;
- default:
- break;
- }
- switch (info.id.iface) {
- case SND_CONTROL_IFACE_CARD: s = "global"; break;
- case SND_CONTROL_IFACE_HWDEP: s = "hwdep"; break;
- case SND_CONTROL_IFACE_MIXER: s = "mixer"; break;
- case SND_CONTROL_IFACE_PCM: s = "pcm"; break;
- case SND_CONTROL_IFACE_RAWMIDI: s = "rawmidi"; break;
- case SND_CONTROL_IFACE_TIMER: s = "timer"; break;
- case SND_CONTROL_IFACE_SEQUENCER: s = "sequencer"; break;
- default: sprintf(v, "%i", info.id.iface); s = v; break;
- }
- fprintf(out, "%scontrol(ident={iface=%s", space, s);
- if (info.id.device > 0)
- fprintf(out, ", device=%i", info.id.device);
- if (info.id.subdevice > 0)
- fprintf(out, ", subdevice=%i", info.id.subdevice);
- fprintf(out, ", name='%s'", info.id.name);
- if (info.id.index > 0)
- fprintf(out, ", index=%i", info.id.index);
- fprintf(out, "}, ");
- switch (info.type) {
- case SND_CONTROL_TYPE_BOOLEAN: fprintf(out, "bool={"); break;
- case SND_CONTROL_TYPE_INTEGER: fprintf(out, "int={"); break;
- case SND_CONTROL_TYPE_ENUMERATED: fprintf(out, "enum={"); break;
- case SND_CONTROL_TYPE_BYTES: fprintf(out, "byte={"); break;
- default: break;
- }
- for (idx = 0; idx < info.values_count; idx++) {
- if (idx > 0)
- fprintf(out, ",");
- switch (info.type) {
- case SND_CONTROL_TYPE_BOOLEAN:
- fprintf(out, "%s", control->c.value.integer.value[idx] ? "true" : "false");
- break;
- case SND_CONTROL_TYPE_INTEGER:
- fprintf(out, "%li", control->c.value.integer.value[idx]);
- break;
- case SND_CONTROL_TYPE_ENUMERATED:
- fprintf(out, "%u", control->c.value.enumerated.item[idx]);
- break;
- case SND_CONTROL_TYPE_BYTES:
- fprintf(out, "%02x", control->c.value.bytes.data[idx]);
- break;
- default:
- break;
- }
- }
- fprintf(out, "})\n");
-}
-
-static void soundcard_setup_write_controls(FILE *out, const char *space, int card, struct ctl_control **controls)
-{
- struct ctl_control *ctl;
-
- if (!(*controls))
- return;
- for (ctl = *controls; ctl; ctl = ctl->next)
- soundcard_setup_write_control(out, space, card, ctl);
-}
-
-#define MAX_LINE (32 * 1024)
-
-int soundcard_setup_write(const char *cfgfile, int cardno)
-{
- FILE *out, *out1, *out2, *in;
- char *tmpfile1, *tmpfile2;
- struct soundcard *first, *sel = NULL;
- char *line, cardname[sizeof(first->control.hwinfo.name)+16], *ptr1;
- int mark, size, ok;
-
- tmpfile1 = (char *)malloc(strlen(cfgfile) + 16);
- tmpfile2 = (char *)malloc(strlen(cfgfile) + 16);
- if (!tmpfile1 || !tmpfile2) {
- error("No enough memory...\n");
- if (tmpfile1)
- free(tmpfile1);
- if (tmpfile2)
- free(tmpfile2);
- return 1;
- }
- strcpy(tmpfile1, cfgfile);
- strcat(tmpfile1, ".new");
- strcpy(tmpfile2, cfgfile);
- strcat(tmpfile2, ".insert");
-
- if (cardno >= 0) {
- line = (char *)malloc(MAX_LINE);
- if (!line) {
- error("No enough memory...\n");
- return 1;
- }
- if ((in = fopen(cfgfile, "r")) == NULL)
- cardno = -1;
- } else {
- line = NULL;
- in = NULL;
- }
- if ((out = out1 = fopen(tmpfile1, "w+")) == NULL) {
- error("Cannot open file '%s' for writing...\n", tmpfile1);
- return 1;
- }
- fprintf(out, "# ALSA driver configuration\n");
- fprintf(out, "# This configuration is generated with the alsactl program.\n");
- fprintf(out, "\n");
- if (cardno >= 0) {
- if ((out = out2 = fopen(tmpfile2, "w+")) == NULL) {
- error("Cannot open file '%s' for writing...\n", tmpfile2);
- return 1;
- }
- } else {
- out2 = NULL;
- }
- for (first = soundcards; first; first = first->next) {
- if (cardno >= 0 && first->no != cardno)
- continue;
- sel = first;
- fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
- if (first->control.controls) {
- soundcard_setup_write_controls(out, " ", first->no, &first->control.controls);
- }
- fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : "");
- }
- /* merge the old and new text */
- if (cardno >= 0) {
- fseek(out2, 0, SEEK_SET);
- mark = ok = 0;
- __1:
- while (fgets(line, MAX_LINE - 1, in)) {
- line[MAX_LINE - 1] = '\0';
- if (!strncmp(line, "soundcard(", 10))
- break;
- }
- while (!feof(in)) {
- ptr1 = line + 10;
- while (*ptr1 && *ptr1 != '"')
- ptr1++;
- if (*ptr1)
- ptr1++;
- strncpy(cardname, sel->control.hwinfo.id, sizeof(sel->control.hwinfo.id));
- cardname[sizeof(sel->control.hwinfo.id)] = '\0';
- strcat(cardname, "\"");
- if (!strncmp(ptr1, cardname, strlen(cardname))) {
- if (mark)
- fprintf(out1, "\n");
- do {
- size = fread(line, 1, MAX_LINE, out2);
- if (size > 0)
- fwrite(line, 1, size, out1);
- } while (size > 0);
- mark = ok = 1;
- goto __1;
- } else {
- if (mark)
- fprintf(out1, "\n");
- fprintf(out1, line);
- while (fgets(line, MAX_LINE - 1, in)) {
- line[MAX_LINE - 1] = '\0';
- fprintf(out1, line);
- if (line[0] == '}') {
- mark = 1;
- goto __1;
- }
- }
- }
- }
- if (!ok) {
- if (mark)
- fprintf(out1, "\n");
- do {
- size = fread(line, 1, MAX_LINE, out2);
- printf("size = %i\n", size);
- if (size > 0)
- fwrite(line, 1, size, out1);
- } while (size > 0);
- }
- }
- if (in)
- fclose(in);
- if (out2)
- fclose(out2);
- if (!access(cfgfile, F_OK) && remove(cfgfile))
- error("Cannot remove file '%s'...", cfgfile);
- if (rename(tmpfile1, cfgfile) < 0)
- error("Cannot rename file '%s' to '%s'...", tmpfile1, cfgfile);
- fclose(out1);
- if (line)
- free(line);
- if (tmpfile2) {
- remove(tmpfile2);
- free(tmpfile2);
- }
- if (tmpfile1) {
- remove(tmpfile1);
- free(tmpfile1);
- }
- return 0;
-}