]> git.alsa-project.org Git - alsa-utils.git/commitdiff
Restore user-defined TLV
authorTakashi Iwai <tiwai@suse.de>
Fri, 25 Aug 2006 09:48:10 +0000 (11:48 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 25 Aug 2006 09:48:10 +0000 (11:48 +0200)
Restore user-defined TLV (mainly for PCM softvol plugin).
TLV is stored in comment.tlv as a hex string.

alsactl/state.c

index 70c8585aa89cedeb0f28c562ee3560a86e342761..3610797777655cdc1e4af76f09d996f500128922 100644 (file)
@@ -128,6 +128,66 @@ static int snd_config_compound_add(snd_config_t *father, const char *id, int joi
        return 0;
 }
 
+#define MAX_USER_TLV_SIZE      64
+
+static char *tlv_to_str(unsigned int *tlv)
+{
+       int i, len = tlv[1] / 4 + 2;
+       char *s, *p;
+
+       if (len >= MAX_USER_TLV_SIZE)
+               return NULL;
+       s = malloc(len * 8 + 1);
+       if (! s)
+               return NULL;
+       p = s;
+       for (i = 0; i < len; i++) {
+               sprintf(p, "%08x", tlv[i]);
+               p += 8;
+       }
+       return s;
+}
+
+static int hextodigit(int c)
+{
+       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
+               return -1;
+       return c;
+}
+
+static unsigned int *str_to_tlv(const char *s)
+{
+       int i, j, c, len;
+       unsigned int *tlv;
+                       
+       len = strlen(s);
+       if (len % 8) /* aligned to 4 bytes (= 8 letters) */
+               return NULL;
+       len /= 8;
+       if (len > MAX_USER_TLV_SIZE)
+               return NULL;
+       tlv = malloc(sizeof(int) * len);
+       if (! tlv)
+               return NULL;
+       for (i = 0; i < len; i++) {
+               tlv[i] = 0;
+               for (j = 0; j < 8; j++) {
+                       if ((c = hextodigit(*s++)) < 0) {
+                               free(tlv);
+                               return NULL;
+                       }
+                       tlv[i] = (tlv[i] << 4) | c;
+               }
+       }
+       return tlv;
+}
+
 static int get_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id, snd_config_t *top)
 {
        snd_ctl_elem_value_t *ctl;
@@ -225,6 +285,23 @@ 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;
                }
+               if (snd_ctl_elem_info_is_tlv_readable(info) &&
+                   snd_ctl_elem_info_is_tlv_writable(info)) {
+                       unsigned int tlv[MAX_USER_TLV_SIZE];
+                       err = snd_ctl_elem_tlv_read(handle, id, tlv, sizeof(tlv));
+                       if (err >= 0) {
+                               char *s = tlv_to_str(tlv);
+                               if (s) {
+                                       err = snd_config_string_add(comment, "tlv", s);
+                                       if (err < 0) {
+                                               error("snd_config_string_add: %s", snd_strerror(err));
+                                               return err;
+                                       }
+                                       free(s);
+                               }
+                       }
+               }
+                   
                break;
        }
        case SND_CTL_ELEM_TYPE_INTEGER64:
@@ -660,10 +737,12 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
        snd_ctl_elem_type_t ctype;
        unsigned int count;
        int err;
+       unsigned int *tlv;
 
        imin = imax = istep = 0;
        count = 0;
        ctype = SND_CTL_ELEM_TYPE_NONE;
+       tlv = NULL;
        snd_config_for_each(i, next, conf) {
                snd_config_t *n = snd_config_iterator_entry(i);
                const char *id, *type;
@@ -708,6 +787,16 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
                        count = v;
                        continue;
                }
+               if (strcmp(id, "tlv") == 0) {
+                       const char *s;
+                       if ((err = snd_config_get_string(n, &s)) < 0)
+                               return -EINVAL;
+                       if (tlv)
+                               free(tlv);
+                       if ((tlv = str_to_tlv(s)) == NULL)
+                               return -EINVAL;
+                       continue;
+               }
        }
 
        snd_ctl_elem_id_alloca(&id);
@@ -719,6 +808,12 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
                if (imin > imax || istep > imax - imin)
                        return -EINVAL;
                err = snd_ctl_elem_add_integer(handle, id, count, imin, imax, istep);
+               if (err < 0)
+                       goto error;
+               if (tlv) {
+                       fprintf(stderr, "XXX write TLV...\n");
+                       snd_ctl_elem_tlv_write(handle, id, tlv);
+               }
                break;
        case SND_CTL_ELEM_TYPE_BOOLEAN:
                err = snd_ctl_elem_add_boolean(handle, id, count);
@@ -731,6 +826,8 @@ static int add_user_control(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_co
                break;
        }
 
+ error:
+       free(tlv);
        if (err < 0)
                return err;
        return snd_ctl_elem_info(handle, info);
@@ -968,13 +1065,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control)
                        }
                        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 {
+                               if ((c = hextodigit(c)) < 0) {
                                        error("bad control.%d.value contents\n", numid);
                                        return -EINVAL;
                                }