diff options
Diffstat (limited to 'mixer.c')
-rw-r--r-- | mixer.c | 85 |
1 files changed, 65 insertions, 20 deletions
@@ -33,6 +33,7 @@ #include <fcntl.h> #include <errno.h> #include <ctype.h> +#include <limits.h> #include <sys/ioctl.h> @@ -209,6 +210,17 @@ void mixer_ctl_update(struct mixer_ctl *ctl) ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); } +unsigned int mixer_ctl_get_id(struct mixer_ctl *ctl) +{ + if (!ctl) + return UINT_MAX; + + /* numid values start at 1, return a 0-base value that + * can be passed to mixer_get_ctl() + */ + return ctl->info->id.numid - 1; +} + const char *mixer_ctl_get_name(struct mixer_ctl *ctl) { if (!ctl) @@ -259,14 +271,11 @@ unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl) static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) { - int range; - - if (percent > 100) - percent = 100; - else if (percent < 0) - percent = 0; + if ((percent > 100) || (percent < 0)) { + return -EINVAL; + } - range = (ei->value.integer.max - ei->value.integer.min); + int range = (ei->value.integer.max - ei->value.integer.min); return ei->value.integer.min + (range * percent) / 100; } @@ -334,7 +343,7 @@ int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id) int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) { struct snd_ctl_elem_value ev; - int ret; + int ret = 0; size_t size; void *source; @@ -344,21 +353,41 @@ int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) 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: + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; 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; + /* check if this is new bytes TLV */ + if (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + struct snd_ctl_tlv *tlv; + int ret; + + tlv = calloc(1, sizeof(*tlv) + count); + tlv->numid = ctl->info->id.numid; + tlv->length = count; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_READ, tlv); + + source = tlv->tlv; + memcpy(array, source, count); + + free(tlv); + + return ret; + } else { + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + size = sizeof(ev.value.bytes.data[0]); + source = ev.value.bytes.data; + break; + } default: return -EINVAL; @@ -383,9 +412,6 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) if (ret < 0) return ret; - if (value > mixer_ctl_get_range_max(ctl)) - value = mixer_ctl_get_range_max(ctl); - switch (ctl->info->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: ev.value.integer.value[id] = !!value; @@ -404,6 +430,10 @@ int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) ev.value.enumerated.item[id] = value; break; + case SNDRV_CTL_ELEM_TYPE_BYTES: + ev.value.bytes.data[id] = value; + break; + default: return -EINVAL; } @@ -431,8 +461,23 @@ int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) break; case SNDRV_CTL_ELEM_TYPE_BYTES: - size = sizeof(ev.value.bytes.data[0]); - dest = ev.value.bytes.data; + /* check if this is new bytes TLV */ + if (ctl->info->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + struct snd_ctl_tlv *tlv; + int ret = 0; + tlv = calloc(1, sizeof(*tlv) + count); + tlv->numid = ctl->info->id.numid; + tlv->length = count; + memcpy(tlv->tlv, array, count); + + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_TLV_WRITE, tlv); + free(tlv); + + return ret; + } else { + size = sizeof(ev.value.bytes.data[0]); + dest = ev.value.bytes.data; + } break; default: |