From 9698d03a63b89fd5a2a2d775bcfc542812da54d9 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Mon, 9 Jan 2017 12:23:14 +0530 Subject: mixer: Add support for TLV RW access check api Tinyalsa doesn't expose an api to check TLV RW access Add mixer_ctl_is_access_tlv_rw(). This api will get used by tinymix and audio HALs for checking TLV RW access before managing the byte related mixer controls. Change-Id: Ib5707fabf479de638e1c7abd4cd149e7637ff9c2 Signed-off-by: Pankaj Bharadiya --- include/tinyalsa/mixer.h | 2 ++ src/mixer.c | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/tinyalsa/mixer.h b/include/tinyalsa/mixer.h index d82d4b1..b9d6cf3 100644 --- a/include/tinyalsa/mixer.h +++ b/include/tinyalsa/mixer.h @@ -107,6 +107,8 @@ const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, unsigned int enum_i */ void mixer_ctl_update(struct mixer_ctl *ctl); +int mixer_ctl_is_access_tlv_rw(const struct mixer_ctl *ctl); + /* Set and get mixer controls */ int mixer_ctl_get_percent(const struct mixer_ctl *ctl, unsigned int id); diff --git a/src/mixer.c b/src/mixer.c index 66881e9..daa04f7 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -381,6 +381,17 @@ void mixer_ctl_update(struct mixer_ctl *ctl) ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); } +/** Checks the control for TLV Read/Write access. + * @param ctl An initialized control handle. + * @returns On success, non-zero. + * On failure, zero. + * @ingroup libtinyalsa-mixer + */ +int mixer_ctl_is_access_tlv_rw(const struct mixer_ctl *ctl) +{ + return (ctl->info.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE); +} + /** Gets the control's ID. * @param ctl An initialized control handle. * @returns On success, the control's ID is returned. @@ -598,7 +609,7 @@ int mixer_ctl_get_array(const struct mixer_ctl *ctl, void *array, size_t count) case SNDRV_CTL_ELEM_TYPE_BYTES: /* check if this is new bytes TLV */ - if (ctl->info.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + if (mixer_ctl_is_access_tlv_rw(ctl)) { struct snd_ctl_tlv *tlv; int ret; @@ -719,7 +730,7 @@ int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) case SNDRV_CTL_ELEM_TYPE_BYTES: /* check if this is new bytes TLV */ - if (ctl->info.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + if (mixer_ctl_is_access_tlv_rw(ctl)) { struct snd_ctl_tlv *tlv; int ret = 0; if (count > SIZE_MAX - sizeof(*tlv)) -- cgit v1.2.3 From 3f813e47784674a3909fe1277bc10b70d03791e2 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Mon, 9 Jan 2017 13:42:14 +0530 Subject: Fix the byte control set/get method The TLV byte controls expect a TLV header as well. Check for TLV access and add TLV header size before invoking mixer API. Change-Id: I12ba129e5bbc0676e80eb920e85b3683decfe0db Signed-off-by: Pawse, GuruprasadX Signed-off-by: Pankaj Bharadiya --- include/tinyalsa/mixer.h | 3 +++ src/mixer.c | 28 ++++++++++++++++++++++++++-- utils/tinymix.c | 30 ++++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/include/tinyalsa/mixer.h b/include/tinyalsa/mixer.h index b9d6cf3..0a48b6f 100644 --- a/include/tinyalsa/mixer.h +++ b/include/tinyalsa/mixer.h @@ -41,6 +41,9 @@ extern "C" { #endif +/* TLV header size*/ +#define TLV_HEADER_SIZE (2 * sizeof(unsigned int)) + struct mixer; struct mixer_ctl; diff --git a/src/mixer.c b/src/mixer.c index daa04f7..b7239fd 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -590,8 +590,20 @@ int mixer_ctl_get_array(const struct mixer_ctl *ctl, void *array, size_t count) int ret = 0; size_t size; void *source; + size_t total_count; - if (!ctl || (count > ctl->info.count) || !count || !array) + if ((!ctl) || !count || !array) + return -EINVAL; + + total_count = ctl->info.count; + + if ((ctl->info.type == SNDRV_CTL_ELEM_TYPE_BYTES) && + (mixer_ctl_is_access_tlv_rw(ctl))) { + /* Additional two words is for the TLV header */ + total_count += TLV_HEADER_SIZE; + } + + if (count > total_count) return -EINVAL; memset(&ev, 0, sizeof(ev)); @@ -714,8 +726,20 @@ int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) struct snd_ctl_elem_value ev; size_t size; void *dest; + size_t total_count; + + if ((!ctl) || !count || !array) + return -EINVAL; + + total_count = ctl->info.count; + + if ((ctl->info.type == SNDRV_CTL_ELEM_TYPE_BYTES) && + (mixer_ctl_is_access_tlv_rw(ctl))) { + /* Additional TLV header */ + total_count += TLV_HEADER_SIZE; + } - if (!ctl || (count > ctl->info.count) || !count || !array) + if (count > total_count) return -EINVAL; memset(&ev, 0, sizeof(ev)); diff --git a/utils/tinymix.c b/utils/tinymix.c index ff3ca7b..a7e7c05 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -192,6 +192,7 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) int min, max; int ret; char *buf = NULL; + unsigned int tlv_header_size = 0; if (isdigit(control[0])) ctl = mixer_get_ctl(mixer, atoi(control)); @@ -207,13 +208,16 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) num_values = mixer_ctl_get_num_values(ctl); if ((type == MIXER_CTL_TYPE_BYTE) && (num_values > 0)) { - buf = calloc(1, num_values); + if (mixer_ctl_is_access_tlv_rw(ctl) != 0) { + tlv_header_size = TLV_HEADER_SIZE; + } + buf = calloc(1, num_values + tlv_header_size); if (buf == NULL) { fprintf(stderr, "Failed to alloc mem for bytes %u\n", num_values); return; } - ret = mixer_ctl_get_array(ctl, buf, num_values); + ret = mixer_ctl_get_array(ctl, buf, num_values + tlv_header_size); if (ret < 0) { fprintf(stderr, "Failed to mixer_ctl_get_array\n"); free(buf); @@ -234,7 +238,8 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) tinymix_print_enum(ctl); break; case MIXER_CTL_TYPE_BYTE: - printf("%02x", buf[i]); + /* skip printing TLV header if exists */ + printf(" %02x", buf[i + tlv_header_size]); break; default: printf("unknown"); @@ -262,13 +267,25 @@ static void tinymix_set_byte_ctl(struct mixer_ctl *ctl, char *end; unsigned int i; long n; + unsigned int *tlv, tlv_size; + unsigned int tlv_header_size = 0; + + if (mixer_ctl_is_access_tlv_rw(ctl) != 0) { + tlv_header_size = TLV_HEADER_SIZE; + } - buf = calloc(1, num_values); + tlv_size = num_values + tlv_header_size; + + buf = calloc(1, tlv_size); if (buf == NULL) { fprintf(stderr, "set_byte_ctl: Failed to alloc mem for bytes %u\n", num_values); exit(EXIT_FAILURE); } + tlv = (unsigned int *)buf; + tlv[0] = 0; + tlv[1] = num_values; + for (i = 0; i < num_values; i++) { errno = 0; n = strtol(values[i], &end, 0); @@ -286,10 +303,11 @@ static void tinymix_set_byte_ctl(struct mixer_ctl *ctl, values[i]); goto fail; } - buf[i] = n; + /* start filling after tlv header */ + buf[i + tlv_header_size] = n; } - ret = mixer_ctl_set_array(ctl, buf, num_values); + ret = mixer_ctl_set_array(ctl, buf, tlv_size); if (ret < 0) { fprintf(stderr, "Failed to set binary control\n"); goto fail; -- cgit v1.2.3