Update tinypcminfo to display format information
[android-sdk/platform-external-tinyalsa.git] / mixer.c
diff --git a/mixer.c b/mixer.c
index a7f5d21a05fda44f7045e51a16ce16ea8f494c11..4568cca2bfed71746b551b397f2a12e09207b894 100644 (file)
--- a/mixer.c
+++ b/mixer.c
@@ -34,6 +34,8 @@
 #include <errno.h>
 #include <ctype.h>
 
+#include <sys/ioctl.h>
+
 #include <linux/ioctl.h>
 #define __force
 #define __bitwise
@@ -50,7 +52,8 @@ struct mixer_ctl {
 
 struct mixer {
     int fd;
-    struct snd_ctl_elem_info *info;
+    struct snd_ctl_card_info card_info;
+    struct snd_ctl_elem_info *elem_info;
     struct mixer_ctl *ctl;
     unsigned int count;
 };
@@ -77,8 +80,8 @@ void mixer_close(struct mixer *mixer)
         free(mixer->ctl);
     }
 
-    if (mixer->info)
-        free(mixer->info);
+    if (mixer->elem_info)
+        free(mixer->elem_info);
 
     free(mixer);
 
@@ -109,8 +112,11 @@ struct mixer *mixer_open(unsigned int card)
         goto fail;
 
     mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
-    mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
-    if (!mixer->ctl || !mixer->info)
+    mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
+    if (!mixer->ctl || !mixer->elem_info)
+        goto fail;
+
+    if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
         goto fail;
 
     eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
@@ -125,7 +131,7 @@ struct mixer *mixer_open(unsigned int card)
         goto fail;
 
     for (n = 0; n < mixer->count; n++) {
-        struct snd_ctl_elem_info *ei = mixer->info + n;
+        struct snd_ctl_elem_info *ei = mixer->elem_info + n;
         ei->id.numid = eid[n].numid;
         if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
             goto fail;
@@ -163,6 +169,11 @@ fail:
     return 0;
 }
 
+const char *mixer_get_name(struct mixer *mixer)
+{
+    return (const char *)mixer->card_info.name;
+}
+
 unsigned int mixer_get_num_ctls(struct mixer *mixer)
 {
     if (!mixer)
@@ -187,19 +198,23 @@ struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
         return NULL;
 
     for (n = 0; n < mixer->count; n++)
-        if (!strcmp(name, (char*) mixer->info[n].id.name))
+        if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
             return mixer->ctl + n;
 
     return NULL;
 }
 
-int mixer_ctl_get_name(struct mixer_ctl *ctl, char *name, unsigned int size)
+void mixer_ctl_update(struct mixer_ctl *ctl)
 {
-    if (!ctl || !name || (size == 0))
-        return -EINVAL;
+    ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
+}
 
-    strncpy(name, (char *)ctl->info->id.name, size);
-    return 0;
+const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
+{
+    if (!ctl)
+        return NULL;
+
+    return (const char *)ctl->info->id.name;
 }
 
 enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
@@ -316,6 +331,44 @@ int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
     return 0;
 }
 
+int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
+{
+    struct snd_ctl_elem_value ev;
+    int ret;
+    size_t size;
+    void *source;
+
+    if (!ctl || (count > ctl->info->count) || !count || !array)
+        return -EINVAL;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.id.numid = ctl->info->id.numid;
+
+    ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
+    if (ret < 0)
+        return ret;
+
+    switch (ctl->info->type) {
+    case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+    case SNDRV_CTL_ELEM_TYPE_INTEGER:
+        size = sizeof(ev.value.integer.value[0]);
+        source = ev.value.integer.value;
+        break;
+
+    case SNDRV_CTL_ELEM_TYPE_BYTES:
+        size = sizeof(ev.value.bytes.data[0]);
+        source = ev.value.bytes.data;
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    memcpy(array, source, size * count);
+
+    return 0;
+}
+
 int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
 {
     struct snd_ctl_elem_value ev;
@@ -350,37 +403,52 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
     return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
 }
 
-int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
+int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
 {
     struct snd_ctl_elem_value ev;
-    int ret;
+    size_t size;
+    void *dest;
 
-    if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
+    if (!ctl || (count > ctl->info->count) || !count || !array)
         return -EINVAL;
 
     memset(&ev, 0, sizeof(ev));
     ev.id.numid = ctl->info->id.numid;
-    ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
-    if (ret < 0)
-        return ret;
+
+    switch (ctl->info->type) {
+    case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+    case SNDRV_CTL_ELEM_TYPE_INTEGER:
+        size = sizeof(ev.value.integer.value[0]);
+        dest = ev.value.integer.value;
+        break;
+
+    case SNDRV_CTL_ELEM_TYPE_BYTES:
+        size = sizeof(ev.value.bytes.data[0]);
+        dest = ev.value.bytes.data;
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    memcpy(dest, array, size * count);
+
+    return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
+int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
+{
+    if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
+        return -EINVAL;
 
     return ctl->info->value.integer.min;
 }
 
 int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
 {
-    struct snd_ctl_elem_value ev;
-    int ret;
-
     if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
         return -EINVAL;
 
-    memset(&ev, 0, sizeof(ev));
-    ev.id.numid = ctl->info->id.numid;
-    ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
-    if (ret < 0)
-        return ret;
-
     return ctl->info->value.integer.max;
 }
 
@@ -392,24 +460,14 @@ unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
     return ctl->info->value.enumerated.items;
 }
 
-int mixer_ctl_get_enum_string(struct mixer_ctl *ctl, unsigned int enum_id,
-                              char *string, unsigned int size)
+const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
+                                      unsigned int enum_id)
 {
-    struct snd_ctl_elem_value ev;
-    int ret;
-
     if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
         (enum_id >= ctl->info->value.enumerated.items))
-        return -EINVAL;
-
-    memset(&ev, 0, sizeof(ev));
-    ev.id.numid = ctl->info->id.numid;
-    ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
-    if (ret < 0)
-        return ret;
-    strncpy(string, (char *)ctl->ename[enum_id], size);
+        return NULL;
 
-    return 0;
+    return (const char *)ctl->ename[enum_id];
 }
 
 int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)