Imported Upstream version 1.0.28
[platform/upstream/alsa-utils.git] / amixer / amixer.c
index a0a7387..cf82892 100644 (file)
@@ -138,11 +138,6 @@ static int info(void)
        return 0;
 }
 
-static const char *control_iface(snd_ctl_elem_id_t *id)
-{
-       return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id));
-}
-
 static const char *control_type(snd_ctl_elem_info_t *info)
 {
        return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info));
@@ -208,62 +203,6 @@ static int convert_prange(long val, long min, long max)
 #define convert_prange1(val, min, max) \
        ceil((val) * ((max) - (min)) * 0.01 + (min))
 
-static long get_integer(char **ptr, long min, long max)
-{
-       long val = min;
-       char *p = *ptr, *s;
-
-       if (*p == ':')
-               p++;
-       if (*p == '\0' || (!isdigit(*p) && *p != '-'))
-               goto out;
-
-       s = p;
-       val = strtol(s, &p, 10);
-       if (*p == '.') {
-               p++;
-               strtol(p, &p, 10);
-       }
-       if (*p == '%') {
-               val = (long)convert_prange1(strtod(s, NULL), min, max);
-               p++;
-       }
-       val = check_range(val, min, max);
-       if (*p == ',')
-               p++;
- out:
-       *ptr = p;
-       return val;
-}
-
-static long get_integer64(char **ptr, long long min, long long max)
-{
-       long long val = min;
-       char *p = *ptr, *s;
-
-       if (*p == ':')
-               p++;
-       if (*p == '\0' || (!isdigit(*p) && *p != '-'))
-               goto out;
-
-       s = p;
-       val = strtol(s, &p, 10);
-       if (*p == '.') {
-               p++;
-               strtol(p, &p, 10);
-       }
-       if (*p == '%') {
-               val = (long long)convert_prange1(strtod(s, NULL), min, max);
-               p++;
-       }
-       val = check_range(val, min, max);
-       if (*p == ',')
-               p++;
- out:
-       *ptr = p;
-       return val;
-}
-
 struct volume_ops {
        int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max);
        int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
@@ -425,10 +364,10 @@ static int set_volume_simple(snd_mixer_elem_t *elem,
                                invalid = 1;
                        if (*p == '+') {
                                val = orig + val;
-                               correct = -1;
+                               correct = 1;
                        } else {
                                val = orig - val;
-                               correct = 1;
+                               correct = -1;
                        }
                }
                p++;
@@ -476,20 +415,12 @@ static int simple_skip_word(char **ptr, char *str)
                
 static void show_control_id(snd_ctl_elem_id_t *id)
 {
-       unsigned int index, device, subdevice;
-       printf("numid=%u,iface=%s,name='%s'",
-              snd_ctl_elem_id_get_numid(id),
-              control_iface(id),
-              snd_ctl_elem_id_get_name(id));
-       index = snd_ctl_elem_id_get_index(id);
-       device = snd_ctl_elem_id_get_device(id);
-       subdevice = snd_ctl_elem_id_get_subdevice(id);
-       if (index)
-               printf(",index=%i", index);
-       if (device)
-               printf(",device=%i", device);
-       if (subdevice)
-               printf(",subdevice=%i", subdevice);
+       char *str;
+
+       str = snd_ctl_ascii_elem_id_get(id);
+       if (str)
+               printf("%s", str);
+       free(str);
 }
 
 static void print_spaces(unsigned int spaces)
@@ -500,7 +431,11 @@ static void print_spaces(unsigned int spaces)
 
 static void print_dB(long dB)
 {
-       printf("%li.%02lidB", dB / 100, (dB < 0 ? -dB : dB) % 100);
+       if (dB < 0) {
+               printf("-%li.%02lidB", -dB / 100, -dB % 100);
+       } else {
+               printf("%li.%02lidB", dB / 100, dB % 100);
+       }
 }
 
 static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size)
@@ -508,6 +443,7 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_
        unsigned int type = tlv[0];
        unsigned int size;
        unsigned int idx = 0;
+       const char *chmap_type = NULL;
 
        if (tlv_size < 2 * sizeof(unsigned int)) {
                printf("TLV size error!\n");
@@ -524,6 +460,7 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_
        }
        switch (type) {
        case SND_CTL_TLVT_CONTAINER:
+               printf("container\n");
                size += sizeof(unsigned int) -1;
                size /= sizeof(unsigned int);
                while (idx < size) {
@@ -531,8 +468,8 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_
                                printf("TLV size error in compound!\n");
                                return;
                        }
-                       decode_tlv(spaces + 2, tlv + idx, tlv[idx+1]);
-                       idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
+                       decode_tlv(spaces + 2, tlv + idx, tlv[idx+1] + 8);
+                       idx += 2 + (tlv[idx+1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
                }
                break;
        case SND_CTL_TLVT_DB_SCALE:
@@ -560,9 +497,9 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_
                        }
                } else {
                        printf("min=");
-                       print_dB(tlv[2]);
+                       print_dB((int)tlv[2]);
                        printf(",max=");
-                       print_dB(tlv[3]);
+                       print_dB((int)tlv[3]);
                }
                break;
 #endif
@@ -600,9 +537,30 @@ static void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_
                        }
                } else {
                        printf("min=");
-                       print_dB(tlv[2]);
+                       print_dB((int)tlv[2]);
                        printf(",max=");
-                       print_dB(tlv[3]);
+                       print_dB((int)tlv[3]);
+               }
+               break;
+#endif
+#ifdef SND_CTL_TLVT_CHMAP_FIXED
+       case SND_CTL_TLVT_CHMAP_FIXED:
+               chmap_type = "fixed";
+               /* Fall through */
+       case SND_CTL_TLVT_CHMAP_VAR:
+               if (!chmap_type)
+                       chmap_type = "variable";
+               /* Fall through */
+       case SND_CTL_TLVT_CHMAP_PAIRED:
+               if (!chmap_type)
+                       chmap_type = "paired";
+               printf("chmap-%s=", chmap_type);
+
+               while (size > 0) {
+                       printf("%s", snd_pcm_chmap_name(tlv[idx++]));
+                       size -= sizeof(unsigned int);
+                       if (size > 0)
+                               printf(",");
                }
                break;
 #endif
@@ -1086,103 +1044,6 @@ static int selems(int level)
        return 0;
 }
 
-static int parse_control_id(const char *str, snd_ctl_elem_id_t *id)
-{
-       int c, size, numid;
-       char *ptr;
-
-       while (*str == ' ' || *str == '\t')
-               str++;
-       if (!(*str))
-               return -EINVAL;
-       snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);    /* default */
-       while (*str) {
-               if (!strncasecmp(str, "numid=", 6)) {
-                       str += 6;
-                       numid = atoi(str);
-                       if (numid <= 0) {
-                               fprintf(stderr, "amixer: Invalid numid %d\n", numid);
-                               return -EINVAL;
-                       }
-                       snd_ctl_elem_id_set_numid(id, atoi(str));
-                       while (isdigit(*str))
-                               str++;
-               } else if (!strncasecmp(str, "iface=", 6)) {
-                       str += 6;
-                       if (!strncasecmp(str, "card", 4)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
-                               str += 4;
-                       } else if (!strncasecmp(str, "mixer", 5)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
-                               str += 5;
-                       } else if (!strncasecmp(str, "pcm", 3)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
-                               str += 3;
-                       } else if (!strncasecmp(str, "rawmidi", 7)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_RAWMIDI);
-                               str += 7;
-                       } else if (!strncasecmp(str, "timer", 5)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_TIMER);
-                               str += 5;
-                       } else if (!strncasecmp(str, "sequencer", 9)) {
-                               snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_SEQUENCER);
-                               str += 9;
-                       } else {
-                               return -EINVAL;
-                       }
-               } else if (!strncasecmp(str, "name=", 5)) {
-                       char buf[64];
-                       str += 5;
-                       ptr = buf;
-                       size = 0;
-                       if (*str == '\'' || *str == '\"') {
-                               c = *str++;
-                               while (*str && *str != c) {
-                                       if (size < (int)sizeof(buf)) {
-                                               *ptr++ = *str;
-                                               size++;
-                                       }
-                                       str++;
-                               }
-                               if (*str == c)
-                                       str++;
-                       } else {
-                               while (*str && *str != ',') {
-                                       if (size < (int)sizeof(buf)) {
-                                               *ptr++ = *str;
-                                               size++;
-                                       }
-                                       str++;
-                               }
-                       }
-                       *ptr = '\0';
-                       snd_ctl_elem_id_set_name(id, buf);
-               } else if (!strncasecmp(str, "index=", 6)) {
-                       str += 6;
-                       snd_ctl_elem_id_set_index(id, atoi(str));
-                       while (isdigit(*str))
-                               str++;
-               } else if (!strncasecmp(str, "device=", 7)) {
-                       str += 7;
-                       snd_ctl_elem_id_set_device(id, atoi(str));
-                       while (isdigit(*str))
-                               str++;
-               } else if (!strncasecmp(str, "subdevice=", 10)) {
-                       str += 10;
-                       snd_ctl_elem_id_set_subdevice(id, atoi(str));
-                       while (isdigit(*str))
-                               str++;
-               }
-               if (*str == ',') {
-                       str++;
-               } else {
-                       if (*str)
-                               return -EINVAL;
-               }
-       }                       
-       return 0;
-}
-
 static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
 {
        int c, size;
@@ -1231,34 +1092,6 @@ static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
        return 0;
 }
 
-static int get_ctl_enum_item_index(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
-                                  char **ptrp)
-{
-       char *ptr = *ptrp;
-       int items, i, len;
-       const char *name;
-       
-       items = snd_ctl_elem_info_get_items(info);
-       if (items <= 0)
-               return -1;
-
-       for (i = 0; i < items; i++) {
-               snd_ctl_elem_info_set_item(info, i);
-               if (snd_ctl_elem_info(handle, info) < 0)
-                       return -1;
-               name = snd_ctl_elem_info_get_item_name(info);
-               len = strlen(name);
-               if (! strncmp(name, ptr, len)) {
-                       if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
-                               ptr += len;
-                               *ptrp = ptr;
-                               return i;
-                       }
-               }
-       }
-       return -1;
-}
-
 static int cset(int argc, char *argv[], int roflag, int keep_handle)
 {
        int err;
@@ -1266,10 +1099,6 @@ static int cset(int argc, char *argv[], int roflag, int keep_handle)
        snd_ctl_elem_info_t *info;
        snd_ctl_elem_id_t *id;
        snd_ctl_elem_value_t *control;
-       char *ptr;
-       unsigned int idx, count;
-       long tmp;
-       snd_ctl_elem_type_t type;
        snd_ctl_elem_info_alloca(&info);
        snd_ctl_elem_id_alloca(&id);
        snd_ctl_elem_value_alloca(&control);
@@ -1278,7 +1107,7 @@ static int cset(int argc, char *argv[], int roflag, int keep_handle)
                fprintf(stderr, "Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n");
                return -EINVAL;
        }
-       if (parse_control_id(argv[0], id)) {
+       if (snd_ctl_ascii_elem_id_parse(id, argv[0])) {
                fprintf(stderr, "Wrong control identifier: %s\n", argv[0]);
                return -EINVAL;
        }
@@ -1303,66 +1132,28 @@ static int cset(int argc, char *argv[], int roflag, int keep_handle)
                }
                return err;
        }
-       snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
-       type = snd_ctl_elem_info_get_type(info);
-       count = snd_ctl_elem_info_get_count(info);
-       snd_ctl_elem_value_set_id(control, id);
-       
+       snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
        if (!roflag) {
-               ptr = argv[1];
-               for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
-                       switch (type) {
-                       case SND_CTL_ELEM_TYPE_BOOLEAN:
-                               tmp = 0;
-                               if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) {
-                                       tmp = 1;
-                                       ptr += 2;
-                               } else if (!strncasecmp(ptr, "yes", 3)) {
-                                       tmp = 1;
-                                       ptr += 3;
-                               } else if (!strncasecmp(ptr, "toggle", 6)) {
-                                       tmp = snd_ctl_elem_value_get_boolean(control, idx);
-                                       tmp = tmp > 0 ? 0 : 1;
-                                       ptr += 6;
-                               } else if (isdigit(*ptr)) {
-                                       tmp = atoi(ptr) > 0 ? 1 : 0;
-                                       while (isdigit(*ptr))
-                                               ptr++;
-                               } else {
-                                       while (*ptr && *ptr != ',')
-                                               ptr++;
-                               }
-                               snd_ctl_elem_value_set_boolean(control, idx, tmp);
-                               break;
-                       case SND_CTL_ELEM_TYPE_INTEGER:
-                               tmp = get_integer(&ptr,
-                                                 snd_ctl_elem_info_get_min(info),
-                                                 snd_ctl_elem_info_get_max(info));
-                               snd_ctl_elem_value_set_integer(control, idx, tmp);
-                               break;
-                       case SND_CTL_ELEM_TYPE_INTEGER64:
-                               tmp = get_integer64(&ptr,
-                                                 snd_ctl_elem_info_get_min64(info),
-                                                 snd_ctl_elem_info_get_max64(info));
-                               snd_ctl_elem_value_set_integer64(control, idx, tmp);
-                               break;
-                       case SND_CTL_ELEM_TYPE_ENUMERATED:
-                               tmp = get_ctl_enum_item_index(handle, info, &ptr);
-                               if (tmp < 0)
-                                       tmp = get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1);
-                               snd_ctl_elem_value_set_enumerated(control, idx, tmp);
-                               break;
-                       case SND_CTL_ELEM_TYPE_BYTES:
-                               tmp = get_integer(&ptr, 0, 255);
-                               snd_ctl_elem_value_set_byte(control, idx, tmp);
-                               break;
-                       default:
-                               break;
+               snd_ctl_elem_value_set_id(control, id);
+               if ((err = snd_ctl_elem_read(handle, control)) < 0) {
+                       if (ignore_error)
+                               return 0;
+                       error("Cannot read the given element from control %s\n", card);
+                       if (! keep_handle) {
+                               snd_ctl_close(handle);
+                               handle = NULL;
                        }
-                       if (!strchr(argv[1], ','))
-                               ptr = argv[1];
-                       else if (*ptr == ',')
-                               ptr++;
+                       return err;
+               }
+               err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]);
+               if (err < 0) {
+                       if (!ignore_error)
+                               error("Control %s parse error: %s\n", card, snd_strerror(err));
+                       if (!keep_handle) {
+                               snd_ctl_close(handle);
+                               handle = NULL;
+                       }
+                       return ignore_error ? 0 : err;
                }
                if ((err = snd_ctl_elem_write(handle, control)) < 0) {
                        if (!ignore_error)