]> git.alsa-project.org Git - alsa-utils.git/commitdiff
Support user-defined controls
authorTakashi Iwai <tiwai@suse.de>
Mon, 3 Jan 2005 11:56:27 +0000 (11:56 +0000)
committerTakashi Iwai <tiwai@suse.de>
Mon, 3 Jan 2005 11:56:27 +0000 (11:56 +0000)
Support store/restore of user-defined controls.
Also, the numid is no longer checked when -F option is given.
The element is determined only from the given name, iface, index, device and
subdevice.

alsactl/alsactl.c

index 4b921531e94c363e46e99b70bb807dddfcd9d7af..ce494d1363d8b19300d73433c9c507f89f3cde4b 100644 (file)
@@ -218,6 +218,8 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
                strcat(buf, " volatile");
        if (snd_ctl_elem_info_is_locked(info))
                strcat(buf, " locked");
+       if (snd_ctl_elem_info_is_user(info))
+               strcat(buf, " user");
        err = snd_config_string_add(comment, "access", buf + 1);
        if (err < 0) {
                error("snd_config_string_add: %s", snd_strerror(err));
@@ -236,6 +238,11 @@ static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *t
                error("snd_config_string_add: %s", snd_strerror(err));
                return err;
        }
+       err = snd_config_integer_add(comment, "count", count);
+       if (err < 0) {
+               error("snd_config_integer_add: %s", snd_strerror(err));
+               return err;
+       }
 
        switch (type) {
        case SND_CTL_ELEM_TYPE_BOOLEAN:
@@ -662,6 +669,106 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle,
        return -1;
 }
 
+static int is_user_control(snd_config_t *conf)
+{
+       snd_config_iterator_t i, next;
+
+       snd_config_for_each(i, next, conf) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               const char *id, *s;
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+               if (strcmp(id, "access") == 0) {
+                       if (snd_config_get_string(n, &s) < 0)
+                               return 0;
+                       if (strstr(s, "user"))
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_config_t *conf)
+{
+       snd_config_iterator_t i, next;
+       long imin, imax, istep;
+       snd_ctl_elem_type_t ctype;
+       unsigned int count;
+       int err;
+
+       imin = imax = istep = 0;
+       count = 0;
+       ctype = SND_CTL_ELEM_TYPE_NONE;
+       snd_config_for_each(i, next, conf) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               const char *id, *type;
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+               if (strcmp(id, "type") == 0) {
+                       if ((err = snd_config_get_string(n, &type)) < 0)
+                               return -EINVAL;
+                       if (strcmp(type, "BOOLEAN") == 0)
+                               ctype = SND_CTL_ELEM_TYPE_BOOLEAN;
+                       else if (strcmp(type, "INTEGER") == 0)
+                               ctype = SND_CTL_ELEM_TYPE_INTEGER;
+                       else if (strcmp(type, "IEC958") == 0)
+                               ctype = SND_CTL_ELEM_TYPE_IEC958;
+                       else
+                               return -EINVAL;
+                       continue;
+               }
+               if (strcmp(id, "range") == 0) {
+                       const char *s;
+                       if ((err = snd_config_get_string(n, &s)) < 0)
+                               return -EINVAL;
+                       switch (ctype) {
+                       case SND_CTL_ELEM_TYPE_INTEGER:
+                               err = sscanf(s, "%li - %li (step %li)", &imin, &imax, &istep);
+                               if (err != 3) {
+                                       istep = 0;
+                                       err = sscanf(s, "%li - %li", &imin, &imax);
+                                       if (err != 2)
+                                               return -EINVAL;
+                               }
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       continue;
+               }
+               if (strcmp(id, "count") == 0) {
+                       long v;
+                       if ((err = snd_config_get_integer(n, &v)) < 0)
+                               return err;
+                       count = v;
+                       continue;
+               }
+       }
+
+       if (count <= 0)
+               count = 1;
+       switch (ctype) {
+       case SND_CTL_ELEM_TYPE_INTEGER:
+               if (imin > imax || istep > imax - imin)
+                       return -EINVAL;
+               err = snd_ctl_elem_add_integer(handle, info, count, imin, imax, istep);
+               break;
+       case SND_CTL_ELEM_TYPE_BOOLEAN:
+               err = snd_ctl_elem_add_boolean(handle, info, count);
+               break;
+       case SND_CTL_ELEM_TYPE_IEC958:
+               err = snd_ctl_elem_add_iec958(handle, info);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       if (err < 0)
+               return err;
+       return snd_ctl_elem_info(handle, info);
+}
+
 static int set_control(snd_ctl_t *handle, snd_config_t *control)
 {
        snd_ctl_elem_value_t *ctl;
@@ -682,6 +789,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
        long index1;
        long index = -1;
        snd_config_t *value = NULL;
+       snd_config_t *comment = NULL;
        long val;
        long long lval;
        unsigned int idx;
@@ -705,8 +813,14 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
                const char *fld;
                if (snd_config_get_id(n, &fld) < 0)
                        continue;
-               if (strcmp(fld, "comment") == 0)
+               if (strcmp(fld, "comment") == 0) {
+                       if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
+                               error("control.%d.%s is invalid", numid, fld);
+                               return -EINVAL;
+                       }
+                       comment = n;
                        continue;
+               }
                if (strcmp(fld, "iface") == 0) {
                        iface = (snd_ctl_elem_iface_t)config_iface(n);
                        if (iface < 0) {
@@ -778,6 +892,14 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
                        snd_ctl_elem_info_set_name(info, name);
                        snd_ctl_elem_info_set_index(info, index);
                        err = snd_ctl_elem_info(handle, info);
+                       if (err < 0 && comment && is_user_control(comment)) {
+                               err = add_user_control(handle, info, comment);
+                               if (err < 0) {
+                                       error("failed to add user control #%d (%s)",
+                                             numid, snd_strerror(err));
+                                       return err;
+                               }
+                       }
                }
        }
        if (err < 0) {
@@ -792,7 +914,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
        index1 = snd_ctl_elem_info_get_index(info);
        count = snd_ctl_elem_info_get_count(info);
        type = snd_ctl_elem_info_get_type(info);
-       if (numid != numid1)
+       if (numid != numid1 && ! force_restore)
                error("warning: numid mismatch (%d/%d) for control #%d", 
                      numid, numid1, numid);
        if (iface != iface1)