]> git.alsa-project.org Git - alsa-utils.git/commitdiff
Rewritten alsactl
authorAbramo Bagnara <abramo@alsa-project.org>
Fri, 25 Aug 2000 14:34:26 +0000 (14:34 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Fri, 25 Aug 2000 14:34:26 +0000 (14:34 +0000)
alsactl/Makefile.am
alsactl/alsactl.c
alsactl/alsactl.h [deleted file]
alsactl/alsactl_lexer.l [deleted file]
alsactl/alsactl_parser.y [deleted file]
alsactl/merge.c [deleted file]
alsactl/setup.c [deleted file]

index 3df506744fc6d2a81ac5bcde009298fa473edf6f..b0d2fa55f996b438c68f3790b0c4184b71e14316 100644 (file)
@@ -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
index cdd81f74966ca64d274fea74814172cc9815d413..2f8b69eaadf0d845620e290472c22848117c4b28 100644 (file)
@@ -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
  *
  */
 
-#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 (file)
index 89df00a..0000000
+++ /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 (file)
index 7253c16..0000000
+++ /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 (file)
index 8eef8ff..0000000
+++ /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 (file)
index 46d87f1..0000000
+++ /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 (file)
index 8385268..0000000
+++ /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;
-}