From 464c2f8b61855cb22d61c4b232f74d6767fac5fb Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Mon, 3 Aug 2020 23:57:45 +0800 Subject: [PATCH 01/48] conf: USB-Audio: Disable IEC958 on Lenovo ThinkStation P620 Both USB audio cards on Lenovo ThinkStation P620 don't support IEC958, so disable IEC958 accordingly. Signed-off-by: Kai-Heng Feng Signed-off-by: Takashi Iwai --- src/conf/cards/USB-Audio.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf index 297629f34..9b64af3c0 100644 --- a/src/conf/cards/USB-Audio.conf +++ b/src/conf/cards/USB-Audio.conf @@ -63,6 +63,8 @@ USB-Audio.pcm.iec958_device { "Scarlett 2i4 USB" 999 "Sennheiser USB headset" 999 "SWTOR Gaming Headset by Razer" 999 + "ThinkStation P620 Main" 999 + "ThinkStation P620 Rear" 999 "Thunderbolt Dock Audio Headset" 999 "Thunderbolt Dock Audio Module" 999 "USB Device 0x46d_0x821" 999 From 82cb27c165d4337fe3183668bd0fa21ff6287e8e Mon Sep 17 00:00:00 2001 From: Vijay Palaniswamy Date: Thu, 23 Jul 2020 11:49:10 +0530 Subject: [PATCH 02/48] pcm: dmix: fix access to sum-buffer in non-interleaved mixing mode When dmix uses non-interleaved mixing mode the offset and step width to sum_buffer was calculated by using the dmix channels instead of the slave channels. This leads to audio distortions due to frame corruption. example: - With below configuratio, Do aplay on both device in parallel for audio distortion pcm.dmix_2_channels { type dmix ipc_key 5678293 ipc_perm 0660 ipc_gid audio bindings [0 1] slave { pcm "hardware" channels 2 periods 4 period_time 40000 } } pcm.dmix_1_channels { type dmix ipc_key 5678293 ipc_perm 0660 ipc_gid audio bindings [0] slave { pcm "hardware" channels 1 periods 4 period_time 40000 } } pcm.hardware { type hw card 0 channels 2 rate 48000 format S16_LE } Signed-off-by: Vijay Palaniswamy Signed-off-by: Takashi Iwai --- src/pcm/pcm_dmix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index e9343b19a..8bce7aca8 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -212,10 +212,10 @@ static void mix_areas(snd_pcm_direct_t *dmix, do_mix_areas(size, ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, - dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, + dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, dst_step, src_step, - channels * sizeof(signed int)); + dmix->shmptr->s.channels * sizeof(signed int)); } } @@ -280,10 +280,10 @@ static void remix_areas(snd_pcm_direct_t *dmix, do_remix_areas(size, ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, - dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, + dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, dst_step, src_step, - channels * sizeof(signed int)); + dmix->shmptr->s.channels * sizeof(signed int)); } } From fece8073860e8bfb1725b288b2b0d74ac6e04434 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Sat, 15 Aug 2020 20:35:55 +0300 Subject: [PATCH 03/48] README: add patch submission instructions Signed-off-by: Tanu Kaskinen Signed-off-by: Takashi Iwai --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 3cd122d51..56af78d04 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,14 @@ http://www.alsa-project.org/alsa-doc/alsa-lib/ You may give a look for more information about the ALSA project to URL http://www.alsa-project.org. + +### Submitting patches + +The preferred way to submit patches is by sending them by email to the +alsa-devel mailing list. Sending mail to the list requires subscription, +subscribe here: https://mailman.alsa-project.org/mailman/listinfo/alsa-devel + +Add Takashi Iwai `` and/or Jaroslav Kysela `` to +Cc so that your patch won't be missed. + +Patches are also accepted as GitHub pull requests. From e097dd491a8f25418a90d38aea549bb4668de955 Mon Sep 17 00:00:00 2001 From: "Tanjeff-N. Moos" Date: Fri, 14 Aug 2020 08:40:28 +0200 Subject: [PATCH 04/48] control: Add documentation for snd_ctl_elem_list_*. Signed-off-by: Tanjeff-N. Moos Signed-off-by: Takashi Iwai --- include/control.h | 81 +++++++++++++++++++++++++++++++++++++++++-- src/control/control.c | 80 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 148 insertions(+), 13 deletions(-) diff --git a/include/control.h b/include/control.h index 02db72d41..9deec6f3d 100644 --- a/include/control.h +++ b/include/control.h @@ -56,7 +56,75 @@ typedef struct _snd_ctl_card_info snd_ctl_card_info_t; /** CTL element identifier container */ typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t; -/** CTL element identifier list container */ +/** CTL element list container + * + * This is a list of CTL elements. The list contains management + * information (e.g. how many elements the sound card has) as well as + * the element identifiers. All functions which operate on the list + * are named snd_ctl_elem_list_*(). + * + * \par Memory management + * + * There are two memory areas to deal with: The list container itself + * and the memory for the element identifiers. + * + * To manage the area for the list container, the following functions + * are used: + * + * - snd_ctl_elem_list_malloc() / snd_ctl_elem_list_free() to allocate + * and free memory on the heap, or + * - snd_ctl_elem_list_alloca() to allocate the memory on the + * stack. This memory is auto-released when the stack is unwound. + * + * To manage the space for the element identifiers, the + * snd_ctl_elem_list_alloc_space() and snd_ctl_elem_list_free_space() + * are used. Allocating the right amount of space can be achieved by + * first obtaining the number of elements and then calling + * snd_ctl_elem_list_alloc_space(): + * + * \code + * snd_ctl_elem_list_t* list; + * int count; + * + * // Initialise list + * snd_ctl_elem_list_malloc(&list); + * + * // Get number of elements + * snd_ctl_elem_list(ctl, list); + * count = snd_ctl_elem_list_get_count(list); + * + * // Allocate space for identifiers + * snd_ctl_elem_list_alloc_space(list, count); + * + * // Get identifiers + * snd_ctl_elem_list(ctl, list); // yes, this is same as above :) + * + * // Do something useful with the list... + * + * // Cleanup + * snd_ctl_elem_list_free_space(list); + * snd_ctl_elem_list_free(list); + * \endcode + * + * + * \par The Elements + * + * The elements in the list are accessed using an index. This index is + * the location in the list; Don't confuse it with the 'index' of the + * element identifier. For example: + * + * \code + * snd_ctl_elem_list_t list; + * unsigned int element_index; + * + * // Allocate space, fill list ... + * + * element_index = snd_ctl_elem_list_get_index(&list, 2); + * \endcode + * + * This will access the 3rd element in the list (index=2) and get the + * elements index from the driver (which might be 13, for example). + */ typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; /** CTL element info container */ @@ -354,11 +422,18 @@ void snd_ctl_event_copy(snd_ctl_event_t *dst, const snd_ctl_event_t *src); snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj); size_t snd_ctl_elem_list_sizeof(void); + /** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_list_t using standard alloca - * \param ptr returned pointer + * + * \brief Allocate a #snd_ctl_elem_list_t using standard alloca. + * + * The memory is allocated on the stack and will automatically be + * released when the stack unwinds (i.e. no free() is needed). + * + * \param ptr Pointer to allocated memory. */ #define snd_ctl_elem_list_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_list) + int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj); void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj); diff --git a/src/control/control.c b/src/control/control.c index e21e8f1d2..1bcf1ab2e 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -280,6 +280,21 @@ int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) /** * \brief Get a list of element identifiers + * + * Before calling this function, memoru must be allocated using + * snd_ctl_elem_list_malloc(). + * + * This function obtains data from the sound card driver and puts it + * into the list. + * + * If there was space allocated for the element identifiers (using + * snd_ctl_elem_list_alloc_space()), information will be filled in. If + * too little space was allocated, only a part of the elements will be + * queried. If there was too much space allocated, some of it remains + * unused. Use snd_ctl_elem_list_get_count() and + * snd_ctl_elem_list_get_used() to obtain information about space + * usage. See #snd_ctl_elem_list_t to learn more. + * * \param ctl CTL handle * \param list CTL element identifiers list pointer * \return 0 on success otherwise a negative error code @@ -1508,9 +1523,14 @@ const char *snd_ctl_event_type_name(snd_ctl_event_type_t type) /** * \brief allocate space for CTL element identifiers list - * \param obj CTL element identifiers list - * \param entries Entries to allocate - * \return 0 on success otherwise a negative error code + * + * The space can be released with snd_ctl_elem_list_free_space(). + * + * \param obj CTL element identifiers list. + * \param entries How many entries to allocate. See + * #snd_ctl_elem_list_t to learn how to obtain + * this number in advance. + * \return 0 on success otherwise a negative error code. */ int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries) { @@ -1526,6 +1546,10 @@ int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries /** * \brief free previously allocated space for CTL element identifiers list + * + * Releases space previously allocated using + * snd_ctl_elem_list_alloc_space(). + * * \param obj CTL element identifiers list */ void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj) @@ -2016,7 +2040,7 @@ snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj) } /** - * \brief get size of #snd_ctl_elem_list_t + * \brief get size of #snd_ctl_elem_list_t. * \return size in bytes */ size_t snd_ctl_elem_list_sizeof() @@ -2025,7 +2049,10 @@ size_t snd_ctl_elem_list_sizeof() } /** - * \brief allocate an invalid #snd_ctl_elem_list_t using standard malloc + * \brief allocate a #snd_ctl_elem_list_t using standard malloc. + * + * The memory can be released using snd_ctl_elem_list_free(). + * * \param ptr returned pointer * \return 0 on success otherwise negative error code */ @@ -2039,7 +2066,15 @@ int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr) } /** - * \brief frees a previously allocated #snd_ctl_elem_list_t + * \brief frees a previously allocated #snd_ctl_elem_list_t. + * + * Release memory previously allocated using + * snd_ctl_elem_list_malloc(). + * + * If you used snd_ctl_elem_list_alloc_space() on the list, you must + * use snd_ctl_elem_list_free_space() \em before calling this + * function. + * * \param obj pointer to object to free */ void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj) @@ -2048,7 +2083,15 @@ void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj) } /** - * \brief clear given #snd_ctl_elem_list_t object + * \brief Clear given #snd_ctl_elem_list_t object. + * + * This will make the stored identifiers inaccessible without freeing + * their space. + * + * \warning The element identifier space cannot be freed after calling + * this function. Therefore, snd_ctl_elem_list_free_space() + * must be called in advance. + * * \param obj pointer to object to clear */ void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj) @@ -2057,7 +2100,11 @@ void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj) } /** - * \brief copy one #snd_ctl_elem_list_t to another + * \brief copy one #snd_ctl_elem_list_t to another. + * + * This performs a shallow copy. That means the both lists will share + * the same space for the elements. The elements will not be copied. + * * \param dst pointer to destination * \param src pointer to source */ @@ -2080,6 +2127,12 @@ void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val) /** * \brief Get number of used entries in CTL element identifiers list + * + * This function returns how many entries are actually filled with + * useful information. + * + * See also snd_ctl_elem_list_get_count(). + * * \param obj CTL element identifier list * \return number of used entries */ @@ -2090,7 +2143,14 @@ unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj) } /** - * \brief Get total count of elements present in CTL device (information present in every filled CTL element identifiers list) + * \brief Get total count of elements present in CTL device + * + * This function returns how many entries were allocated using + * snd_ctl_elem_list_alloc_space(). This information is present after + * snd_ctl_elem_list() was called. + * + * See also snd_ctl_elem_list_get_used(). + * * \param obj CTL element identifier list * \return total number of elements */ @@ -2140,7 +2200,7 @@ snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t * } /** - * \brief Get device part of CTL element identifier for an entry of a CTL element identifiers list + * \brief Get the device part of CTL element identifier for an entry of a CTL element identifiers list * \param obj CTL element identifier list * \param idx Index of entry * \return CTL element related device From ed752498522b0a99a9fbec99247d9c73b10abb3e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 18 Aug 2020 16:53:23 +0200 Subject: [PATCH 05/48] conf: quote also strings with '*' and '#' characters in string_print() Signed-off-by: Jaroslav Kysela --- src/conf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/conf.c b/src/conf.c index 8518f90c5..7df2b4e77 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1536,6 +1536,8 @@ static void string_print(char *str, int id, snd_output_t *out) case ']': case '\'': case '"': + case '*': + case '#': goto quoted; default: if (*p <= 31 || *p >= 127) From 1ac965184eaefe503939e454273223a1d8d32f41 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:54 +0200 Subject: [PATCH 06/48] topology: decode: Fix channel map memory allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Memory allocated on the stack was referenced outside of the function scope caused undefined behaviour. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 90241b631..6e6c1d163 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1330,7 +1330,6 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, void *bin, size_t size) { struct snd_soc_tplg_enum_control *ec = bin; - struct snd_tplg_channel_map_template cmt; int i; if (size < sizeof(*ec)) { @@ -1375,11 +1374,13 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, } } - et->map = &cmt; - memset(&cmt, 0, sizeof(cmt)); - cmt.num_channels = ec->num_channels; - for (i = 0; i < cmt.num_channels; i++) { - struct snd_tplg_channel_elem *channel = &cmt.channel[i]; + et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template)); + if (!et->map) + return -ENOMEM; + et->map->num_channels = ec->num_channels; + for (i = 0; i < et->map->num_channels; i++) { + struct snd_tplg_channel_elem *channel = &et->map->channel[i]; + tplg_log(tplg, 'D', pos + ((void *)&ec->channel[i] - (void *)ec), "enum: channel size %d", ec->channel[i].size); channel->reg = ec->channel[i].reg; From 346a5efa87c38a0d5ff9bd5b5d08be27b6c9bfaf Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:55 +0200 Subject: [PATCH 07/48] topology: decode: Fix infinite loop in decoding enum control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing memory outside of allocated boundaries caused segmentation fault. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 6e6c1d163..0aa49ab82 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1367,7 +1367,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); if (!et->texts) return -ENOMEM; - for (i = 0; ec->items; i++) { + for (i = 0; i < ec->items; i++) { unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE; et->texts[i] = ec->texts[i]; et->values[i] = (int *)&ec->values[j]; From 11d4a5aa721dce2c3f7430996caf244a73dd5099 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:56 +0200 Subject: [PATCH 08/48] topology: decode: Remove decoding values for enum control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Values have no representation in standard ALSA configuration files, therefore there is no need to populate them. Also memory for values wasn't allocated which was causing undefined behaviour. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 0aa49ab82..02e482e7d 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1367,11 +1367,8 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); if (!et->texts) return -ENOMEM; - for (i = 0; i < ec->items; i++) { - unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE; + for (i = 0; i < ec->items; i++) et->texts[i] = ec->texts[i]; - et->values[i] = (int *)&ec->values[j]; - } } et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template)); From f1435207a2fbe35bf616c6d58eecd8801dbe5642 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:57 +0200 Subject: [PATCH 09/48] topology: decode: Add enum control texts as separate element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Texts are separate sections that should referenced by enum control. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 02e482e7d..1f3984616 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1088,11 +1088,19 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, } if (enum_ctl->texts != NULL) { + struct tplg_elem *texts = tplg_elem_new_common(tplg, NULL, + enum_ctl->hdr.name, SND_TPLG_TYPE_TEXT); + + texts->texts->num_items = num_items; for (i = 0; i < num_items; i++) { - if (enum_ctl->texts[i] != NULL) - snd_strlcpy(ec->texts[i], enum_ctl->texts[i], - SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (!enum_ctl->texts[i]) + continue; + snd_strlcpy(ec->texts[i], enum_ctl->texts[i], + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + snd_strlcpy(texts->texts->items[i], enum_ctl->texts[i], + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); } + tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, enum_ctl->hdr.name); } if (enum_ctl->values != NULL) { From 56a096ca2ceaf1dec944258d961c274e6550b27a Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:58 +0200 Subject: [PATCH 10/48] topology: decode: Fix printing texts section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topology/text.c b/src/topology/text.c index 507c5450a..b899b2813 100644 --- a/src/topology/text.c +++ b/src/topology/text.c @@ -103,7 +103,7 @@ int tplg_save_text(snd_tplg_t *tplg ATTRIBUTE_UNUSED, return 0; err = tplg_save_printf(dst, pfx, "'%s'.values [\n", elem->id); for (i = 0; err >= 0 && i < texts->num_items; i++) - err = tplg_save_printf(dst, pfx, "\t'%s'\n", texts->items[i][0]); + err = tplg_save_printf(dst, pfx, "\t'%s'\n", texts->items[i]); if (err >= 0) err = tplg_save_printf(dst, pfx, "]\n"); return err; From c32498603aea7cc2f3fa3f850f9e4ea0f6ce03b2 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:08:59 +0200 Subject: [PATCH 11/48] topology: decode: Change declaration of enum decoding function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Size constraints are always checked before invoking tplg_decode_control_enum1. There is no need to validate it twice. Alos moved debug print about size to invoking function, since now it's it responsibility to check size. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 19 +++++-------------- src/topology/dapm.c | 3 +-- src/topology/tplg_local.h | 2 +- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 1f3984616..47db400fd 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1335,22 +1335,10 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, struct list_head *heap, struct snd_tplg_enum_template *et, size_t pos, - void *bin, size_t size) + struct snd_soc_tplg_enum_control *ec) { - struct snd_soc_tplg_enum_control *ec = bin; int i; - if (size < sizeof(*ec)) { - SNDERR("enum: small size %d", size); - return -EINVAL; - } - - tplg_log(tplg, 'D', pos, "enum: size %d private size %d", - ec->size, ec->priv.size); - if (size != ec->size + ec->priv.size) { - SNDERR("enum: unexpected element size %d", size); - return -EINVAL; - } if (ec->num_channels > SND_TPLG_MAX_CHAN || ec->num_channels > SND_SOC_TPLG_MAX_CHAN) { SNDERR("enum: unexpected channel count %d", ec->num_channels); @@ -1427,7 +1415,10 @@ int tplg_decode_control_enum(snd_tplg_t *tplg, return -EINVAL; } - err = tplg_decode_control_enum1(tplg, &heap, &et, pos, bin, size); + tplg_log(tplg, 'D', pos, "enum: size %d private size %d", + ec->size, ec->priv.size); + + err = tplg_decode_control_enum1(tplg, &heap, &et, pos, ec); if (err >= 0) { t.enum_ctl = &et; err = snd_tplg_add_object(tplg, &t); diff --git a/src/topology/dapm.c b/src/topology/dapm.c index cd1a87704..73a939034 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -972,8 +972,7 @@ int tplg_decode_dapm_widget(snd_tplg_t *tplg, err = -EINVAL; goto retval; } - err = tplg_decode_control_enum1(tplg, &heap, et, pos, - bin, size2); + err = tplg_decode_control_enum1(tplg, &heap, et, pos, ec); break; case SND_SOC_TPLG_TYPE_BYTES: bt = tplg_calloc(&heap, sizeof(*bt)); diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 5ace0d191..acb01a831 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -398,7 +398,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, struct list_head *heap, struct snd_tplg_enum_template *et, size_t pos, - void *bin, size_t size); + struct snd_soc_tplg_enum_control *ec); int tplg_decode_control_enum(snd_tplg_t *tplg, size_t pos, struct snd_soc_tplg_hdr *hdr, void *bin, size_t size); From acbb0e3b1741107d01f03ee06f7819fd7f90bec4 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:09:00 +0200 Subject: [PATCH 12/48] topology: decode: Fix decoding PCM formats and rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not checking _LAST format and rate, which are valid indexes in arrays, makes data loss while converting binary to standard ALSA configuration file. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topology/pcm.c b/src/topology/pcm.c index b15b95045..db401145f 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -549,7 +549,7 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && sc->formats) { err = tplg_save_printf(dst, pfx, "\tformats '"); first = 1; - for (i = 0; err >= 0 && i < SND_PCM_FORMAT_LAST; i++) { + for (i = 0; err >= 0 && i <= SND_PCM_FORMAT_LAST; i++) { if (sc->formats & (1ULL << i)) { s = snd_pcm_format_name(i); err = tplg_save_printf(dst, NULL, "%s%s", @@ -563,7 +563,7 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && sc->rates) { err = tplg_save_printf(dst, pfx, "\trates '"); first = 1; - for (i = 0; err >= 0 && i < SND_PCM_RATE_LAST; i++) { + for (i = 0; err >= 0 && i <= SND_PCM_RATE_LAST; i++) { if (sc->rates & (1ULL << i)) { s = get_rate_name(i); err = tplg_save_printf(dst, NULL, "%s%s", From d93b3462996a20951bc0ca753d0304bbbb9850fc Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:09:01 +0200 Subject: [PATCH 13/48] topology: decode: Print sig_bits field in PCM capabilities section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not printing this field makes data loss while converting from binary to standard ALSA configuration file. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/topology/pcm.c b/src/topology/pcm.c index db401145f..49c5eaba8 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -604,6 +604,9 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && sc->buffer_size_max) err = tplg_save_printf(dst, pfx, "\tbuffer_size_max %u\n", sc->buffer_size_max); + if (err >= 0 && sc->sig_bits) + err = tplg_save_printf(dst, pfx, "\tsig_bits %u\n", + sc->sig_bits); if (err >= 0) err = tplg_save_printf(dst, pfx, "}\n"); return err; From 6b0fb2bc7e0cfac8e1aedfcad183ab247c85173d Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:09:02 +0200 Subject: [PATCH 14/48] topology: decode: Add DAI name printing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DAI name is a part of topology binary. Not printing makes data loss while converting from binary to standard ALSA configuration file. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/pcm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 49c5eaba8..5a54e1534 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -781,7 +781,9 @@ int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct snd_soc_tplg_pcm *pcm = elem->pcm; int err = 0; - if (pcm->dai_id > 0) + if (strlen(pcm->dai_name)) + err = tplg_save_printf(dst, pfx, "dai.'%s'.id %u\n", pcm->dai_name, pcm->dai_id); + else if (pcm->dai_id > 0) err = tplg_save_printf(dst, pfx, "dai.0.id %u\n", pcm->dai_id); return err; } From d04e72c9a593015952e4858b92ab3f9d821560d9 Mon Sep 17 00:00:00 2001 From: Piotr Maziarz Date: Mon, 31 Aug 2020 11:09:03 +0200 Subject: [PATCH 15/48] topology: Make buffer for saving dynamic size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some fields can exceed size limit, e.g. private data has no size restriction. Therefore it needs to be dynamically increased. Signed-off-by: Piotr Maziarz Reviewed-by: Cezary Rojewski Reviewed-by: Amadeusz Sławiński Reviewed-by: Pierre-Louis Bossart Signed-off-by: Jaroslav Kysela --- src/topology/save.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/topology/save.c b/src/topology/save.c index 4ecf86c3a..9c74735ae 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -19,22 +19,43 @@ #include "tplg_local.h" #define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ +#define PRINT_BUF_SIZE (1024) +#define PRINT_BUF_SIZE_MAX (1024 * 1024) int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) { va_list va; - char buf[1024], *s; + char *buf, *s; size_t n, l, t, pl; + int ret = 0; + + buf = malloc(PRINT_BUF_SIZE); + if (!buf) + return -ENOMEM; if (pfx == NULL) pfx = ""; va_start(va, fmt); - n = vsnprintf(buf, sizeof(buf), fmt, va); + n = vsnprintf(buf, PRINT_BUF_SIZE, fmt, va); va_end(va); - if (n >= sizeof(buf)) - return -EOVERFLOW; + if (n >= PRINT_BUF_SIZE_MAX) { + ret = -EOVERFLOW; + goto end; + } + + if (n >= PRINT_BUF_SIZE) { + char *tmp = realloc(buf, n + 1); + if (!tmp) { + ret = -ENOMEM; + goto end; + } + buf = tmp; + va_start(va, fmt); + n = vsnprintf(buf, n + 1, fmt, va); + va_end(va); + } pl = strlen(pfx); l = *dst ? strlen(*dst) : 0; @@ -47,7 +68,8 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) if (s == NULL) { free(*dst); *dst = NULL; - return -ENOMEM; + ret = -ENOMEM; + goto end; } } else { s = *dst; @@ -57,6 +79,8 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) strcpy(s + l, pfx); strcpy(s + l + pl, buf); *dst = s; +end: + free(buf); return 0; } From dc778bade60812a71b98ac827c2c6e3c02f14cf1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2020 13:21:26 +0200 Subject: [PATCH 16/48] topology: return correct value in tplg_save_printf() Signed-off-by: Jaroslav Kysela --- src/topology/save.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topology/save.c b/src/topology/save.c index 9c74735ae..16fd69463 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -81,7 +81,7 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) *dst = s; end: free(buf); - return 0; + return ret; } int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value) From 6ca1ddfbcdf97ad46c3767ba314d1144119361fd Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2020 13:25:01 +0200 Subject: [PATCH 17/48] topology: fix some gcc10 warnings (labs, signess) Signed-off-by: Jaroslav Kysela --- src/topology/builder.c | 2 +- src/topology/ctl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topology/builder.c b/src/topology/builder.c index 15757668d..f8aba8303 100644 --- a/src/topology/builder.c +++ b/src/topology/builder.c @@ -55,7 +55,7 @@ static ssize_t write_block_header(snd_tplg_t *tplg, unsigned int type, " offset 0x%zx is %s by %ld bytes", tplg->next_hdr_pos, tplg->bin_pos, tplg->bin_pos > tplg->next_hdr_pos ? "ahead" : "behind", - labs(tplg->bin_pos - tplg->next_hdr_pos)); + tplg->bin_pos - tplg->next_hdr_pos); return -EINVAL; } diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 47db400fd..1d31b4944 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -1363,7 +1363,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); if (!et->texts) return -ENOMEM; - for (i = 0; i < ec->items; i++) + for (i = 0; (unsigned int)i < ec->items; i++) et->texts[i] = ec->texts[i]; } From 84c6aeef5ca89c0686ae2a9ed90504010f8fe9e6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2020 14:25:56 +0200 Subject: [PATCH 18/48] topology: fix sort_config() The temporary config array must be initialized for all compound types. Signed-off-by: Jaroslav Kysela --- src/topology/save.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/topology/save.c b/src/topology/save.c index 16fd69463..631d84b27 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -143,7 +143,6 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) int index, array, count; if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) { - if (snd_config_copy(&dst, src) >= 0) return dst; return NULL; @@ -155,14 +154,13 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) if (a == NULL) return NULL; array = snd_config_is_array(src); - if (array <= 0) { - index = 0; - snd_config_for_each(i, next, src) { - snd_config_t *s = snd_config_iterator_entry(i); - a[index++] = s; - } - qsort(a, count, sizeof(a[0]), _compar); + index = 0; + snd_config_for_each(i, next, src) { + snd_config_t *s = snd_config_iterator_entry(i); + a[index++] = s; } + if (array <= 0) + qsort(a, count, sizeof(a[0]), _compar); if (snd_config_make_compound(&dst, id, count == 1)) { free(a); return NULL; From ab73253924ad8d46f94ab1212e0f05ebc2e3dcc5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2020 14:27:26 +0200 Subject: [PATCH 19/48] topology: fix the unaligned access Introduce unaligned_get32/put32 helpers to deal with the packed structures. Use the gcc __BYTE_ORDER__ defines for the endian checks. It may be improved to support other compilation environment. Signed-off-by: Jaroslav Kysela --- src/topology/parser.c | 6 ++---- src/topology/pcm.c | 26 ++++++++++++++------------ src/topology/tplg_local.h | 13 +++++++++++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/topology/parser.c b/src/topology/parser.c index 436e48416..f34de01bd 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -427,10 +427,8 @@ void snd_tplg_verbose(snd_tplg_t *tplg, int verbose) static bool is_little_endian(void) { -#ifdef __BYTE_ORDER - #if __BYTE_ORDER == __LITTLE_ENDIAN - return true; - #endif +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_INT__ == 4 + return true; #endif return false; } diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 5a54e1534..a60ba00d9 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -376,19 +376,19 @@ static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str) return 0; } -static int parse_unsigned(snd_config_t *n, unsigned int *dst) +static int parse_unsigned(snd_config_t *n, void *dst) { int ival; if (tplg_get_integer(n, &ival, 0) < 0) return -EINVAL; - *dst = ival; + unaligned_put32(dst, ival); #if TPLG_DEBUG { const char *id; if (snd_config_get_id(n, &id) >= 0) - tplg_dbg("\t\t%s: %d", id, *dst); + tplg_dbg("\t\t%s: %d", id, ival); } #endif return 0; @@ -621,7 +621,7 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem = private; struct snd_soc_tplg_pcm *pcm; struct snd_soc_tplg_dai *dai; - unsigned int *playback, *capture; + void *playback, *capture; struct snd_soc_tplg_stream_caps *caps; const char *id, *value; int stream; @@ -651,10 +651,10 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (strcmp(id, "playback") == 0) { stream = SND_SOC_TPLG_STREAM_PLAYBACK; - *playback = 1; + unaligned_put32(playback, 1); } else if (strcmp(id, "capture") == 0) { stream = SND_SOC_TPLG_STREAM_CAPTURE; - *capture = 1; + unaligned_put32(capture, 1); } else return -EINVAL; @@ -747,6 +747,7 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, snd_config_iterator_t i, next; snd_config_t *n; const char *id; + unsigned int dai_id; snd_config_get_id(cfg, &id); tplg_dbg("\t\tFE DAI %s:", id); @@ -761,12 +762,13 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, continue; if (strcmp(id, "id") == 0) { - if (tplg_get_unsigned(n, &pcm->dai_id, 0)) { + if (tplg_get_unsigned(n, &dai_id, 0)) { SNDERR("invalid fe dai ID"); return -EINVAL; } - tplg_dbg("\t\t\tindex: %d", pcm->dai_id); + unaligned_put32(&pcm->dai_id, dai_id); + tplg_dbg("\t\t\tindex: %d", dai_id); } } @@ -790,7 +792,7 @@ int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, /* parse a flag bit of the given mask */ static int parse_flag(snd_config_t *n, unsigned int mask_in, - unsigned int *mask, unsigned int *flags) + void *mask, void *flags) { int ret; @@ -798,11 +800,11 @@ static int parse_flag(snd_config_t *n, unsigned int mask_in, if (ret < 0) return ret; - *mask |= mask_in; + unaligned_put32(mask, unaligned_get32(mask) | mask_in); if (ret) - *flags |= mask_in; + unaligned_put32(flags, unaligned_get32(flags) | mask_in); else - *flags &= ~mask_in; + unaligned_put32(flags, unaligned_get32(flags) & (~mask_in)); return 0; } diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index acb01a831..0c7be2001 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -225,6 +225,19 @@ struct tplg_table { extern struct tplg_table tplg_table[]; extern unsigned int tplg_table_items; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_INT__ == 4 +static inline unsigned int unaligned_get32(void *src) +{ + unsigned int ret; + memcpy(&ret, src, sizeof(ret)); + return ret; +} +static inline void unaligned_put32(void *dst, unsigned int val) +{ + memcpy(dst, &val, sizeof(val)); +} +#endif + #define tplg_log(tplg, type, pos, fmt, args...) do { \ if ((tplg)->verbose) \ tplg_log_((tplg), (type), (pos), (fmt), ##args); \ From 472ab5db67a0ed04de634214773e7b17d10b5415 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 31 Aug 2020 19:44:46 +0200 Subject: [PATCH 20/48] topology: improve the printf buffer management The commit d04e72c9a593015952e4858b92ab3f9d821560d9 introduced the dynamic printf buffer allocation for each tplg_save_printf() call. Introduce 'struct tplg_buf' which carries extra information about the temporary printf buffer and the destination buffer to save allocation requests. The printf buffer is also allocated using 1024 bytes chunks. A comparison between 'alloc everyting' and 'cache+chunk alloc' for the random picked topology file: 1: 18,620 allocs, 18,620 frees, 7,239,688 bytes allocated 2: 12,490 allocs, 12,490 frees, 962,568 bytes allocated Signed-off-by: Jaroslav Kysela --- src/topology/channel.c | 3 +- src/topology/ctl.c | 14 ++--- src/topology/dapm.c | 5 +- src/topology/data.c | 15 +++--- src/topology/ops.c | 6 +-- src/topology/pcm.c | 18 +++---- src/topology/save.c | 108 +++++++++++++++++++++++--------------- src/topology/text.c | 2 +- src/topology/tplg_local.h | 56 +++++++++++--------- 9 files changed, 130 insertions(+), 97 deletions(-) diff --git a/src/topology/channel.c b/src/topology/channel.c index 47d5ea4c4..ebdff4696 100644 --- a/src/topology/channel.c +++ b/src/topology/channel.c @@ -138,7 +138,8 @@ int tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg, int tplg_save_channels(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct snd_soc_tplg_channel *channel, - unsigned int count, char **dst, const char *pfx) + unsigned int count, struct tplg_buf *dst, + const char *pfx) { struct snd_soc_tplg_channel *c; const char *s; diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 1d31b4944..a38399631 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -105,8 +105,8 @@ int parse_access(snd_config_t *cfg, /* Save Access */ static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED, - struct snd_soc_tplg_ctl_hdr *hdr, char **dst, - const char *pfx) + struct snd_soc_tplg_ctl_hdr *hdr, + struct tplg_buf *dst, const char *pfx) { const char *last; unsigned int j, count, access, cval; @@ -399,7 +399,7 @@ int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg, /* save TLV data */ int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_ctl_tlv *tlv = elem->tlv; struct snd_soc_tplg_tlv_dbscale *scale; @@ -557,7 +557,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg, /* save control bytes */ int tplg_save_control_bytes(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_bytes_control *be = elem->bytes_ext; char pfx2[16]; @@ -697,7 +697,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, /* save control eunm */ int tplg_save_control_enum(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl; char pfx2[16]; @@ -858,8 +858,8 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg, } int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED, - struct tplg_elem *elem, char **dst, - const char *pfx) + struct tplg_elem *elem, + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl; char pfx2[16]; diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 73a939034..46f2f8b3d 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -416,7 +416,8 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, } /* save DAPM graph */ -int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, char **dst, const char *pfx) +int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_dapm_graph_elem *route; struct list_head *pos; @@ -669,7 +670,7 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg, /* save DAPM widget */ int tplg_save_dapm_widget(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_dapm_widget *widget = elem->widget; const char *s; diff --git a/src/topology/data.c b/src/topology/data.c index 5742b3577..3585af309 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -121,7 +121,8 @@ int tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem, /* save references */ int tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, unsigned int type, - const char *id, char **dst, const char *pfx) + const char *id, struct tplg_buf *dst, + const char *pfx) { struct tplg_ref *ref, *last; struct list_head *pos; @@ -890,7 +891,7 @@ static int parse_tuple_set(snd_config_t *cfg, /* save tuple set */ static int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples, unsigned int set_index, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct tplg_tuple_set *set; struct tplg_tuple *tuple; @@ -1014,7 +1015,7 @@ static int parse_tuple_sets(snd_config_t *cfg, /* save tuple sets */ int tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct tplg_vendor_tuples *tuples = elem->tuples; unsigned int i; @@ -1085,7 +1086,7 @@ int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg, /* save vendor tokens */ int tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct tplg_vendor_tokens *tokens = elem->tokens; unsigned int i; @@ -1156,7 +1157,7 @@ int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg, /* save vendor tuples */ int tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { char pfx2[16]; int err; @@ -1242,7 +1243,7 @@ int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg, /* save manifest data */ int tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, - struct tplg_elem *elem, char **dst, + struct tplg_elem *elem, struct tplg_buf *dst, const char *pfx) { struct list_head *pos; @@ -1420,7 +1421,7 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, /* save data element */ int tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_private *priv = elem->data; struct list_head *pos; diff --git a/src/topology/ops.c b/src/topology/ops.c index 110eef588..da1756085 100644 --- a/src/topology/ops.c +++ b/src/topology/ops.c @@ -105,8 +105,8 @@ int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, snd_config_t *cfg, /* save control operations */ int tplg_save_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, - struct snd_soc_tplg_ctl_hdr *hdr, char **dst, - const char *pfx) + struct snd_soc_tplg_ctl_hdr *hdr, + struct tplg_buf *dst, const char *pfx) { const char *s; int err; @@ -191,7 +191,7 @@ int tplg_parse_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, /* save external control operations */ int tplg_save_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct snd_soc_tplg_bytes_control *be, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { const char *s; int err; diff --git a/src/topology/pcm.c b/src/topology/pcm.c index a60ba00d9..191b7a0a9 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -538,7 +538,7 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, /* save stream caps */ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_stream_caps *sc = elem->stream_caps; const char *s; @@ -686,7 +686,7 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, /* Save the caps and config of a pcm stream */ int tplg_save_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { static const char *stream_ids[2] = { "playback", @@ -778,7 +778,7 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, /* Save the caps and config of a pcm stream */ int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_pcm *pcm = elem->pcm; int err = 0; @@ -810,7 +810,7 @@ static int parse_flag(snd_config_t *n, unsigned int mask_in, } static int save_flags(unsigned int flags, unsigned int mask, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { static unsigned int flag_masks[3] = { SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, @@ -944,7 +944,7 @@ int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, /* save PCM */ int tplg_save_pcm(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_pcm *pcm = elem->pcm; char pfx2[16]; @@ -1081,7 +1081,7 @@ int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg, /* save DAI */ int tplg_save_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_dai *dai = elem->dai; char pfx2[16]; @@ -1235,7 +1235,7 @@ int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, /* save physical link */ int tplg_save_link(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_link_config *link = elem->link; char pfx2[16]; @@ -1315,7 +1315,7 @@ int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg, /* save CC */ int tplg_save_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_link_config *link = elem->link; char pfx2[16]; @@ -1611,7 +1611,7 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, /* save hw config */ int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct snd_soc_tplg_hw_config *hc = elem->hw_cfg; int err; diff --git a/src/topology/save.c b/src/topology/save.c index 631d84b27..56250af30 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -19,25 +19,43 @@ #include "tplg_local.h" #define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ -#define PRINT_BUF_SIZE (1024) +#define PRINT_ALLOC_SHIFT (10) /* 1024 bytes */ #define PRINT_BUF_SIZE_MAX (1024 * 1024) +#define NEXT_CHUNK(val, shift) ((((val) >> (shift)) + 1) << (shift)) -int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) +void tplg_buf_init(struct tplg_buf *buf) +{ + buf->dst = NULL; + buf->dst_len = 0; + buf->printf_buf = NULL; + buf->printf_buf_size = 0; +} + +void tplg_buf_free(struct tplg_buf *buf) +{ + free(buf->dst); + free(buf->printf_buf); +} + +char *tplg_buf_detach(struct tplg_buf *buf) +{ + char *ret = buf->dst; + free(buf->printf_buf); + return ret; +} + +int tplg_save_printf(struct tplg_buf *dst, const char *pfx, const char *fmt, ...) { va_list va; - char *buf, *s; + char *s; size_t n, l, t, pl; int ret = 0; - buf = malloc(PRINT_BUF_SIZE); - if (!buf) - return -ENOMEM; - if (pfx == NULL) pfx = ""; va_start(va, fmt); - n = vsnprintf(buf, PRINT_BUF_SIZE, fmt, va); + n = vsnprintf(dst->printf_buf, dst->printf_buf_size, fmt, va); va_end(va); if (n >= PRINT_BUF_SIZE_MAX) { @@ -45,42 +63,41 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) goto end; } - if (n >= PRINT_BUF_SIZE) { - char *tmp = realloc(buf, n + 1); - if (!tmp) { + if (n >= dst->printf_buf_size) { + t = NEXT_CHUNK(n + 1, PRINT_ALLOC_SHIFT); + s = realloc(dst->printf_buf, t); + if (!s) { ret = -ENOMEM; goto end; } - buf = tmp; + dst->printf_buf = s; + dst->printf_buf_size = t; va_start(va, fmt); - n = vsnprintf(buf, n + 1, fmt, va); + n = vsnprintf(dst->printf_buf, n + 1, fmt, va); va_end(va); } pl = strlen(pfx); - l = *dst ? strlen(*dst) : 0; + l = dst->dst_len; t = l + pl + n + 1; /* allocate chunks */ - if (*dst == NULL || + if (dst->dst == NULL || (l >> SAVE_ALLOC_SHIFT) != (t >> SAVE_ALLOC_SHIFT)) { - s = realloc(*dst, ((t >> SAVE_ALLOC_SHIFT) + 1) << - SAVE_ALLOC_SHIFT); + s = realloc(dst->dst, NEXT_CHUNK(t, SAVE_ALLOC_SHIFT)); if (s == NULL) { - free(*dst); - *dst = NULL; ret = -ENOMEM; goto end; } } else { - s = *dst; + s = dst->dst; } if (pl > 0) strcpy(s + l, pfx); - strcpy(s + l + pl, buf); - *dst = s; + strcpy(s + l + pl, dst->printf_buf); + dst->dst = s; + dst->dst_len = t - 1; end: - free(buf); return ret; } @@ -209,7 +226,7 @@ static int tplg_check_quoted(const unsigned char *p) return 0; } -static int tplg_save_quoted(char **dst, const char *str) +static int tplg_save_quoted(struct tplg_buf *dst, const char *str) { static const char nibble[16] = "0123456789abcdef"; unsigned char *p, *d, *t; @@ -263,7 +280,7 @@ static int tplg_save_quoted(char **dst, const char *str) return tplg_save_printf(dst, NULL, "'%s'", d); } -static int tplg_save_string(char **dst, const char *str, int id) +static int tplg_save_string(struct tplg_buf *dst, const char *str, int id) { const unsigned char *p = (const unsigned char *)str; @@ -279,7 +296,7 @@ static int tplg_save_string(char **dst, const char *str, int id) return tplg_save_printf(dst, NULL, "%s", str); } -static int save_config(char **dst, int level, const char *delim, snd_config_t *src) +static int save_config(struct tplg_buf *dst, int level, const char *delim, snd_config_t *src) { snd_config_iterator_t i, next; snd_config_t *s; @@ -400,7 +417,8 @@ static int save_config(char **dst, int level, const char *delim, snd_config_t *s return 0; } -static int tplg_save(snd_tplg_t *tplg, char **dst, int gindex, const char *prefix) +static int tplg_save(snd_tplg_t *tplg, struct tplg_buf *dst, + int gindex, const char *prefix) { struct tplg_table *tptr; struct tplg_elem *elem; @@ -484,8 +502,6 @@ static int tplg_save(snd_tplg_t *tplg, char **dst, int gindex, const char *prefi return 0; _err: - free(*dst); - *dst = NULL; return err; } @@ -540,9 +556,9 @@ static int tplg_index_groups(snd_tplg_t *tplg, int **indexes) int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) { + struct tplg_buf buf, buf2; snd_input_t *in; snd_config_t *top, *top2; - char *dst2; int *indexes, *a; int err; @@ -550,35 +566,41 @@ int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) assert(dst); *dst = NULL; + tplg_buf_init(&buf); + if (flags & SND_TPLG_SAVE_GROUPS) { err = tplg_index_groups(tplg, &indexes); if (err < 0) return err; for (a = indexes; err >= 0 && *a >= 0; a++) { - err = tplg_save_printf(dst, NULL, + err = tplg_save_printf(&buf, NULL, "IndexGroup.%d {\n", *a); if (err >= 0) - err = tplg_save(tplg, dst, *a, "\t"); + err = tplg_save(tplg, &buf, *a, "\t"); if (err >= 0) - err = tplg_save_printf(dst, NULL, "}\n"); + err = tplg_save_printf(&buf, NULL, "}\n"); } free(indexes); } else { - err = tplg_save(tplg, dst, -1, NULL); + err = tplg_save(tplg, &buf, -1, NULL); } if (err < 0) goto _err; - if (*dst == NULL) - return -EINVAL; + if (buf.dst == NULL) { + err = -EINVAL; + goto _err; + } - if (flags & SND_TPLG_SAVE_NOCHECK) + if (flags & SND_TPLG_SAVE_NOCHECK) { + *dst = tplg_buf_detach(&buf); return 0; + } /* always load configuration - check */ - err = snd_input_buffer_open(&in, *dst, strlen(*dst)); + err = snd_input_buffer_open(&in, buf.dst, strlen(buf.dst)); if (err < 0) { SNDERR("could not create input buffer"); goto _err; @@ -610,20 +632,20 @@ int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) top = top2; } - dst2 = NULL; - err = save_config(&dst2, 0, NULL, top); + tplg_buf_init(&buf2); + err = save_config(&buf2, 0, NULL, top); snd_config_delete(top); if (err < 0) { SNDERR("could not save configuration"); goto _err; } - free(*dst); - *dst = dst2; + tplg_buf_free(&buf); + *dst = tplg_buf_detach(&buf2); return 0; _err: - free(*dst); + tplg_buf_free(&buf); *dst = NULL; return err; } diff --git a/src/topology/text.c b/src/topology/text.c index b899b2813..b07feb999 100644 --- a/src/topology/text.c +++ b/src/topology/text.c @@ -93,7 +93,7 @@ int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg, /* save text data */ int tplg_save_text(snd_tplg_t *tplg ATTRIBUTE_UNUSED, struct tplg_elem *elem, - char **dst, const char *pfx) + struct tplg_buf *dst, const char *pfx) { struct tplg_texts *texts = elem->texts; unsigned int i; diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 0c7be2001..d553117e2 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -200,6 +200,14 @@ struct map_elem { int id; }; +/* output buffer */ +struct tplg_buf { + char *dst; + size_t dst_len; + char *printf_buf; + size_t printf_buf_size; +}; + /* mapping table */ struct tplg_table { const char *name; @@ -214,9 +222,9 @@ struct tplg_table { void (*free)(void *); int (*parse)(snd_tplg_t *tplg, snd_config_t *cfg, void *priv); int (*save)(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *prefix); + struct tplg_buf *dst, const char *prefix); int (*gsave)(snd_tplg_t *tplg, int index, - char **dst, const char *prefix); + struct tplg_buf *dst, const char *prefix); int (*decod)(snd_tplg_t *tplg, size_t pos, struct snd_soc_tplg_hdr *hdr, void *bin, size_t size); @@ -348,49 +356,49 @@ int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value); -int tplg_save_printf(char **dst, const char *prefix, const char *fmt, ...); +int tplg_save_printf(struct tplg_buf *dst, const char *prefix, const char *fmt, ...); int tplg_save_refs(snd_tplg_t *tplg, struct tplg_elem *elem, unsigned int type, - const char *id, char **dst, const char *pfx); + const char *id, struct tplg_buf *dst, const char *pfx); int tplg_save_channels(snd_tplg_t *tplg, struct snd_soc_tplg_channel *channel, - unsigned int channel_count, char **dst, const char *pfx); + unsigned int channel_count, struct tplg_buf *dst, const char *pfx); int tplg_save_ops(snd_tplg_t *tplg, struct snd_soc_tplg_ctl_hdr *hdr, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_ext_ops(snd_tplg_t *tplg, struct snd_soc_tplg_bytes_control *be, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_manifest_data(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_control_mixer(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_control_enum(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_control_bytes(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_tlv(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_data(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_text(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_tokens(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_tuples(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_dapm_widget(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_link(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_cc(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_pcm(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_hw_config(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_stream_caps(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_save_dai(snd_tplg_t *tplg, struct tplg_elem *elem, - char **dst, const char *pfx); + struct tplg_buf *dst, const char *pfx); int tplg_decode_template(snd_tplg_t *tplg, size_t pos, From 84185b5c94ec8a214103b8ec02d272f0158c24e6 Mon Sep 17 00:00:00 2001 From: "Tanjeff-N. Moos" Date: Wed, 2 Sep 2020 11:27:26 +0200 Subject: [PATCH 21/48] control: Improve general control interface documentation. Signed-off-by: Tanjeff-N. Moos Signed-off-by: Takashi Iwai --- src/control/control.c | 72 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/src/control/control.c b/src/control/control.c index 1bcf1ab2e..497a5399b 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -31,7 +31,7 @@ /*! \page control Control interface

Control interface is designed to access primitive controls. There is -also interface notifying about control and structure changes. +also an interface for notifying about control and structure changes. \section control_general_overview General overview @@ -43,20 +43,74 @@ are managed according to below model. Some element sets can be added to a sound card by drivers in kernel and userspace applications. - element - - An element can be identified by userspace applications. Each element has - own identical information. + - A control element might be a master volume control, for example, or a + read-only indicator, such as a sync status. An element has a type (e.g. + INTEGER or BOOLEAN) and - depending on the type - min/max values, a step + size, a set of possible values (for enums), etc. - member - - An element includes some members to have a value. The value of each member - can be changed by both of userspace applications and drivers in kernel. -Each element can be identified by two ways; the numerical number (numid), or the -combination of interface, device, subdevice, name, and index. + - An element includes one or more member(s) to have a value. For + example, a stereo volume control element has two members (for + left/right). The members share the same properties (e.g. both + volume controls have the same min/max values). The value of each + member can be changed by both of userspace applications and + drivers in kernel. -The type of element set is one of integer, integerr64, boolean, enumerators, + +\section identifying_elements Identifying the Elements + +Each element has the following identifying properties: + + - The numid (a numeric identifier, assigned when the sound card is + detected, constant while the sound card is kept connected) + + - The interface type (e.g. MIXER, CARD or PCM) + - The device + - The subdevice + - Its name + - Its index + +An element can be identified either by its numid or by the tuple +(interface type, device, subdevice, name, index). This tuple is always +the same (driver updates can change it, but in practice this is +rare). The numid can change on each boot. In case of an USB sound +card, the numid can also change when it is reconnected. + + +\section element_lists Element Lists + +An element list can be used to obtain a list of all elements of the +sound card. The list contains generic information (e.g. how many +elements the card has), and the identifying properties of the elements +(numid, card, name, ...). See #snd_ctl_elem_list_t to learn more about +element lists. + + +\section working_with_elements Working with Elements + +It is possible to obtain information about an element using the +snd_ctl_elem_info_*() functions. For enums, the allowed values can be +obtained, for integers, the min/max values can be obtained, and so +on. In addition, these functions can report the identifying +properties. E.g. when the element is addressed using its numid, the +functions complements the name, index, etc. + +To access the values of a control, use the snd_ctl_elem_value*() +functions. These allow to get and set the actual values or +settings. It is also possible to get and set the ID values (such as +the numid or the name). + + +\section element_sets Element Sets + +The type of element set is one of integer, integer64, boolean, enumerators, bytes and IEC958 structure. This indicates the type of value for each member in elements included in the element set. -When the value of member is changed, corresponding events are transferred to + +\section events Events + +When the value of a member is changed, corresponding events are transferred to userspace applications. The applications should subscribe any events in advance. \section tlv_blob Supplemental data for elements in an element set From c1e72460de5ddcfdc8b93e73952c6fe9d6f60591 Mon Sep 17 00:00:00 2001 From: "Tanjeff-N. Moos" Date: Wed, 2 Sep 2020 11:27:27 +0200 Subject: [PATCH 22/48] control: Add documentation for snd_ctl_elem_value_*. Signed-off-by: Tanjeff-N. Moos Signed-off-by: Takashi Iwai --- include/control.h | 61 +++++- src/control/control.c | 454 ++++++++++++++++++++++++++++-------------- 2 files changed, 357 insertions(+), 158 deletions(-) diff --git a/include/control.h b/include/control.h index 9deec6f3d..8766f4409 100644 --- a/include/control.h +++ b/include/control.h @@ -130,7 +130,53 @@ typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; /** CTL element info container */ typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; -/** CTL element value container */ +/** CTL element value container + * + * Contains the value(s) (i.e. members) of a single element. All + * values of a given element are of the same type. + * + * \par Memory management + * + * To access a value, a snd_ctl_elem_value_t must be allocated using + * snd_ctl_elem_value_alloca() or snd_ctl_elem_value_malloc(). When + * using the latter, it must be freed again using + * snd_ctl_elem_value_free(). + * + * \par Identifier + * + * Then, the ID must be filled. It is sufficient to fill only the + * numid, if known. Otherwise, interface type, device, subdevice, + * name, index must all be given. The following functions can be used + * to fill the ID: + * + * - snd_ctl_elem_value_set_id(): Set the ID. Requires an + * snd_ctl_elem_id_t object. + * - snd_ctl_elem_value_set_numid(): Set the numid. + * - Or use all of the following: + * + * - snd_ctl_elem_value_set_interface() + * - snd_ctl_elem_value_set_device() + * - snd_ctl_elem_value_set_subdevice() + * - snd_ctl_elem_value_set_name() + * - snd_ctl_elem_value_set_index() + * + * When communicating with the driver (snd_ctl_elem_read(), + * snd_ctl_elem_write()), and the numid was given, the interface, + * device, ... are filled (even if you set the before). When the numid + * is unset (i.e. it is 0), it is filled. + * + * \par Communicating with the driver + * + * After the value container was created and filled with the ID of the + * desired element, the value(s) can be fetched from the driver (and + * thus from the hardware) or written to the driver. + * + * To fetch a value, use snd_ctl_elem_read(). Thereafter, use the + * snd_ctl_elem_value_get_*() functions to obtain the actual value. + * + * To write a new value, first use a snd_ctl_elem_value_set_*() to set + * it, then call snd_ctl_elem_write() to write it to the driver. + */ typedef struct _snd_ctl_elem_value snd_ctl_elem_value_t; /** CTL event container */ @@ -529,11 +575,20 @@ int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); size_t snd_ctl_elem_value_sizeof(void); + /** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_value_t using standard alloca - * \param ptr returned pointer + * \brief Allocate an invalid #snd_ctl_elem_value_t on the stack. + * + * Allocate space for a value object on the stack. The allocated + * memory need not be freed, because is on the stack. + * + * See snd_ctl_elem_value_t for details. + * + * \param ptr Pointer to a snd_ctl_elem_value_t pointer. The address + * of the allocated space will returned here. */ #define snd_ctl_elem_value_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_value) + int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr); void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj); void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj); diff --git a/src/control/control.c b/src/control/control.c index 497a5399b..08058c067 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -38,32 +38,39 @@ also an interface for notifying about control and structure changes. In ALSA control feature, each sound card can have control elements. The elements are managed according to below model. - - element set + - Element set + - A set of elements with the same attribute (i.e. name, get/put operations). Some element sets can be added to a sound card by drivers in kernel and userspace applications. - - element + + - Element + - A control element might be a master volume control, for example, or a read-only indicator, such as a sync status. An element has a type (e.g. - INTEGER or BOOLEAN) and - depending on the type - min/max values, a step - size, a set of possible values (for enums), etc. - - member + SNDRV_CTL_ELEM_TYPE_INTEGER or SNDRV_CTL_ELEM_TYPE_BOOLEAN) and - depending + on the type - min/max values, a step size, a set of possible values (for + enums), etc. + + - Member - - An element includes one or more member(s) to have a value. For - example, a stereo volume control element has two members (for - left/right). The members share the same properties (e.g. both - volume controls have the same min/max values). The value of each - member can be changed by both of userspace applications and - drivers in kernel. + - An element usually includes one or more member(s) to have a value. For + example, a stereo volume control element has two members (for left/right), + while a mono volume has only one member. The member count can be obtained + using snd_ctl_elem_info_get_count(). Elements of type + "SNDRV_CTL_ELEM_TYPE_BYTES" or "SNDRV_CTL_ELEM_TYPE_IEC958" have no members + at all (and thus no member count), they have just a single value. The + members share the same properties (e.g. both volume control members have + the same min/max values). The value of each member can be changed by both + of userspace applications and drivers in kernel. -\section identifying_elements Identifying the Elements +\section identifying_elements Identifying Elements Each element has the following identifying properties: - The numid (a numeric identifier, assigned when the sound card is detected, constant while the sound card is kept connected) - - The interface type (e.g. MIXER, CARD or PCM) - The device - The subdevice @@ -95,10 +102,10 @@ on. In addition, these functions can report the identifying properties. E.g. when the element is addressed using its numid, the functions complements the name, index, etc. -To access the values of a control, use the snd_ctl_elem_value*() -functions. These allow to get and set the actual values or -settings. It is also possible to get and set the ID values (such as -the numid or the name). +To access the members (i.e. values) of a control, use the +snd_ctl_elem_value*() functions. These allow to get and set the +actual values or settings. It is also possible to get and set the ID +values (such as the numid or the name). \section element_sets Element Sets @@ -931,10 +938,19 @@ int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) } /** - * \brief Get CTL element value - * \param ctl CTL handle - * \param data Data of an element. - * \return 0 on success otherwise a negative error code + * \brief Get CTL element value. + * + * Read information from sound card. You must set the ID of the + * element before calling this function. + * + * See snd_ctl_elem_value_t for details. + * + * \param ctl CTL handle. + * \param data The element value. The ID must be set before calling + * the function, and the actual value will be returned + * here. + * + * \return 0 on success otherwise a negative error code. */ int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data) { @@ -943,9 +959,16 @@ int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data) } /** - * \brief Set CTL element value - * \param ctl CTL handle - * \param data Data of an element. + * \brief Set CTL element value. + * + * Write new value(s) to the sound card. You must set the ID and the + * value of the element before calling this function. + * + * See snd_ctl_elem_value_t for details. + * + * \param ctl CTL handle. + * \param data The new value. + * * \retval 0 on success * \retval >0 on success when value was changed * \retval <0 a negative error code @@ -2877,9 +2900,16 @@ size_t snd_ctl_elem_value_sizeof() } /** - * \brief Allocate an invalid #snd_ctl_elem_value_t using standard malloc(3). - * \param ptr Returned pointer for data of an element. - * \return 0 on success otherwise negative error code. + * \brief Allocate an invalid #snd_ctl_elem_value_t on the heap. + * + * Allocate space for a value object on the head. The allocated memory + * must be freed using snd_ctl_elem_value_free(). + * + * See snd_ctl_elem_value_t for details. + * + * \param ptr Pointer to a snd_ctl_elem_value_t pointer. The address + * of the allocated space will be returned here. + * \return 0 on success, otherwise a negative error code. */ int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr) { @@ -2891,8 +2921,10 @@ int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr) } /** - * \brief Frees a previously allocated data of an element. - * \param obj Data of an element. + * \brief Free an #snd_ctl_elem_value_t previously allocated using + * snd_ctl_elem_value_malloc(). + * + * \param obj Pointer to the snd_ctl_elem_value_t. */ void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) { @@ -2901,6 +2933,9 @@ void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) /** * \brief Clear given data of an element. + * + * See snd_ctl_elem_value_t for details. + * * \param obj Data of an element. */ void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) @@ -2909,7 +2944,7 @@ void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) } /** - * \brief Copy two data of elements. + * \brief Bitwise copy of a snd_ctl_elem_value_t value. * \param dst Pointer to destination. * \param src Pointer to source. */ @@ -2921,9 +2956,10 @@ void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, } /** - * \brief Compare one data of an element to the other. - * \param left Pointer to first data. - * \param right Pointer to second data. + * \brief Compare two snd_ctl_elem_value_t values, bytewise. + * + * \param left First value. + * \param right Second value. * \return 0 on match, less than or greater than otherwise, see memcmp(3). */ int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, @@ -2934,9 +2970,13 @@ int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, } /** - * \brief Get element identifier from given data of an element. - * \param obj Data of an element. - * \param ptr Pointer for element identifier. + * \brief Get the element identifier from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param ptr Pointer to an identifier object. The identifier is + * stored there. */ void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_t *ptr) { @@ -2945,9 +2985,12 @@ void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_ } /** - * \brief Get element numeric identifier from given data of an element. - * \param obj Data of an element. - * \return Element numeric identifier. + * \brief Get the identifiers 'numid' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The numid. */ unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj) { @@ -2956,10 +2999,12 @@ unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj) } /** - * \brief Get interface part of element identifier from given data of an - * element. - * \param obj Data of an element. - * \return Interface part of element identifier. + * \brief Get the identifiers 'interface' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The interface part of element identifier. */ snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t *obj) { @@ -2968,9 +3013,12 @@ snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t } /** - * \brief Get device part of element identifier from given data of an element. - * \param obj Data of an element. - * \return Device part of element identifier. + * \brief Get the identifiers 'device' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The device part of element identifier. */ unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj) { @@ -2979,10 +3027,12 @@ unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj) } /** - * \brief Get subdevice part of element identifier from given data of an - * element. - * \param obj Data of an element. - * \return Subdevice part of element identifier. + * \brief Get the identifiers 'subdevice' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The subdevice part of element identifier. */ unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj) { @@ -2991,9 +3041,12 @@ unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj) } /** - * \brief Get name part of element identifier from given data of an element. - * \param obj Data of an element. - * \return Name part of element identifier. + * \brief Get the identifiers 'name' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The "name" part of element identifier. */ const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj) { @@ -3002,9 +3055,12 @@ const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj) } /** - * \brief Get index part of element identifier from given data of an element. - * \param obj Data of an element. - * \return Index part of element identifier. + * \brief Get the identifiers 'index' part from the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \return The index part of element identifier. */ unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj) { @@ -3012,10 +3068,14 @@ unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj) return obj->id.index; } + /** - * \brief Set element identifier to given data of an element. - * \param obj Data of an element. - * \param ptr Pointer to an element identifier. + * \brief Set the element identifier within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param ptr The new identifier. */ void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr) { @@ -3024,9 +3084,12 @@ void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_ } /** - * \brief Set numeric identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for numeric identifier. + * \brief Set the identifiers 'numid' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new numid. */ void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val) { @@ -3035,9 +3098,12 @@ void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val) } /** - * \brief Set interface part of element identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for interface part of element identifier. + * \brief Set the identifiers 'interface' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new interface. */ void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_iface_t val) { @@ -3046,9 +3112,12 @@ void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_if } /** - * \brief Set device part of element identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for device part of element identifier. + * \brief Set the identifiers 'device' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new device. */ void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val) { @@ -3057,9 +3126,12 @@ void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val) } /** - * \brief Set subdevice part of element identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for subdevice part of element identifier. + * \brief Set the identifiers 'subdevice' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new subdevice. */ void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val) { @@ -3068,9 +3140,12 @@ void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int va } /** - * \brief Set name part of element identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for name part of element identifier, + * \brief Set the identifiers 'name' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new name. */ void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) { @@ -3079,9 +3154,12 @@ void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) } /** - * \brief Set index part of element identifier to given data of an element. - * \param obj Data of an element. - * \param val Value for index part of element identifier. + * \brief Set the identifiers 'index' part within the given element value. + * + * See snd_ctl_elem_value_t for more details. + * + * \param obj The element value. + * \param val The new index. */ void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) { @@ -3090,12 +3168,16 @@ void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) } /** - * \brief Get value of a specified member from given data as an element of - * boolean type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \return Value for the member. - */ + * \brief Get an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BOOLEAN. It + * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref + * control for more details. + * + * \param obj The element value object + * \param idx The index of the member. + * \return The members value. + */ int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) { assert(obj); @@ -3104,12 +3186,16 @@ int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int } /** - * \brief Get value of a specified member from given data as an element of - * integer type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \return Value for the member. - */ + * \brief Get an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER. It + * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref + * control for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \return The members value. + */ long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) { assert(obj); @@ -3118,12 +3204,16 @@ long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned in } /** - * \brief Get value of a specified member from given data as an element of - * integer64 type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \return Value for the member. - */ + * \brief Get an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER64. It + * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref + * control for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \return The members value. + */ long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) { assert(obj); @@ -3132,12 +3222,16 @@ long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsi } /** - * \brief Get value of a specified member from given data as an element of - * enumerated type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \return Value for the member. This is an index of name set in the element. - */ + * \brief Get an element members value. + * + * Use this function if the element is of type + * SNDRV_CTL_ELEM_TYPE_ENUMERATED. It returns the index of the active item. See + * \ref snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \param idx The index of the requested member. + * \return The index of the active item. + */ unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) { assert(obj); @@ -3146,12 +3240,16 @@ unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, } /** - * \brief Get value of a specified member from given data as an element of - * bytes type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \return Value for the member. - */ + * \brief Get an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTE. It + * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref + * control for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \return The members value. + */ unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) { assert(obj); @@ -3160,12 +3258,16 @@ unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsig } /** - * \brief Set value of a specified member to given data as an element of - * boolean type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \param val Value for the member. - */ + * \brief Set an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BOOLEAN. It + * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control + * for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \param val The new value. + */ void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) { assert(obj); @@ -3174,12 +3276,16 @@ void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, } /** - * \brief Set value of a specified member to given data as an element of - * integer type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \param val Value for the member. - */ + * \brief Set an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER. It + * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control + * for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \param val The new value. + */ void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) { assert(obj); @@ -3188,12 +3294,16 @@ void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, } /** - * \brief Set value of a specified member to given data as an element of - * integer64 type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \param val Value for the member. - */ + * \brief Set an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER64. It + * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control + * for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \param val The new value. + */ void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) { assert(obj); @@ -3202,12 +3312,16 @@ void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int id } /** - * \brief Set value of a specified member to given data as an element of - * enumerated type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \param val Value for the member. - */ + * \brief Set an element members value. + * + * Use this function if the element is of type + * SNDRV_CTL_ELEM_TYPE_ENUMERATED. It activates the specified item. See \ref + * snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \param idx The index of the requested member. + * \param val The new index of the item to be activated. + */ void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) { assert(obj); @@ -3216,12 +3330,16 @@ void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int i } /** - * \brief Set value for a specified member to given data as an element of byte - * type. - * \param obj Data of an element. - * \param idx Index of member in the element. - * \param val Value for the member. - */ + * \brief Set an element members value. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTE. It + * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control + * for more details. + * + * \param obj The element value object. + * \param idx The index of the member. + * \param val The new value. + */ void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) { assert(obj); @@ -3230,10 +3348,17 @@ void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, un } /** - * \brief Set values to given data as an element of bytes type. - * \param obj Data of an element. - * \param data Pointer for byte array. - * \param size The number of bytes included in the memory block. + * \brief Replace the data stored within the element. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTES. It + * replaces the data stored in the element. Note that "bytes" elements don't + * have members. They have only one single block of data. + * + * See \ref snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \param data Pointer to the new data. + * \param size The size of the new data, in bytes. */ void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) { @@ -3243,10 +3368,17 @@ void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) } /** - * \brief Get memory block from given data as an element of bytes type. - * \param obj Data of an element. - * \return Pointer for byte array. - */ + * \brief Get the data stored within the element. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTES. It + * returns the data stored in the element. Note that "bytes" elements don't have + * members. They have only one single block of data. + * + * See \ref snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \return Pointer to the elements data. + */ const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) { assert(obj); @@ -3254,11 +3386,17 @@ const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) } /** - * \brief Get value from given data to given pointer as an element of IEC958 - * type. - * \param obj Data of an element. - * \param ptr Pointer to IEC958 data. - */ + * \brief Get an elements IEC958 data. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_IEC958. Note that + * "IEC958" elements don't have members. They have only one single + * IEC958 information block. + * + * See \ref snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \param ptr Pointer to an IEC958 structure. The data is stored there. + */ void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr) { assert(obj && ptr); @@ -3266,11 +3404,17 @@ void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec9 } /** - * \brief Set value from given pointer to given data as an element of IEC958 - * type. - * \param obj Data of an element. - * \param ptr Pointer to IEC958 data. - */ + * \brief Set an elements IEC958 data. + * + * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_IEC958. Note + * that "IEC958" elements don't have members. They have only one single IEC958 + * information block. + * + * See \ref snd_ctl_elem_value_t and \ref control for more details. + * + * \param obj The element value object. + * \param ptr Pointer to the new IEC958 data. + */ void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr) { assert(obj && ptr); From e80f35611d5de623f1cc1e7f266605b272c7259d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 6 Oct 2020 10:23:25 +0200 Subject: [PATCH 23/48] ucm: Handle 'Error' keyword in the master file With the conditional blocks, it may be useful to terminate the hardware detection from the configuration. Introduce 'Error' keyword for the master UCM configuration file. Signed-off-by: Jaroslav Kysela --- src/ucm/parser.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ucm/parser.c b/src/ucm/parser.c index d034b8598..e57e208a8 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -244,6 +244,24 @@ int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n, return 0; } +/* + * Handle 'Error' configuration node. + */ +static int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) +{ + int err; + char *s; + + err = parse_string_substitute3(uc_mgr, cfg, &s); + if (err < 0) { + uc_error("error: failed to get Error string"); + return err; + } + uc_error("%s", s); + free(s); + return -ENXIO; +} + /* * Evaluate variable regex definitions (in-place delete) */ @@ -1899,6 +1917,10 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) continue; } + /* error */ + if (strcmp(id, "Error") == 0) + return error_node(uc_mgr, n); + uc_error("uknown master file field %s", id); } return 0; From 22d5ca8b6bcd767d09de11b0afdd82c618f4be24 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 6 Oct 2020 10:40:40 +0200 Subject: [PATCH 24/48] ucm: add a check for the empty configuration Return an error if the UCM configuration is empty (no verbs or no boot sequence). Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index 9e43ac66a..00b417089 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -568,6 +568,20 @@ static int import_master_config(snd_use_case_mgr_t *uc_mgr) return add_auto_values(uc_mgr); } +/** + * \brief Check, if the UCM configuration is empty + * \param uc_mgr Use case Manager + * \return zero on success, otherwise a negative error code + */ +static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr) +{ + if (!list_empty(&uc_mgr->verb_list)) + return 0; + if (!list_empty(&uc_mgr->once_list)) + return 0; + return -ENXIO; +} + /** * \brief Universal find - string in a list * \param list List of structures @@ -981,14 +995,20 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, err = import_master_config(mgr); if (err < 0) { uc_error("error: failed to import %s use case configuration %d", - card_name, err); - goto err; + card_name, err); + goto _err; + } + + err = check_empty_configuration(mgr); + if (err < 0) { + uc_error("error: failed to import %s (empty configuration)", card_name); + goto _err; } *uc_mgr = mgr; return 0; -err: +_err: uc_mgr_free(mgr); return err; } From 61749cf40083e02014becc4bdebf4c734a4dc5d3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 6 Oct 2020 10:43:38 +0200 Subject: [PATCH 25/48] ucm: substitute the comment string also in the main configuration file Signed-off-by: Jaroslav Kysela --- src/ucm/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ucm/parser.c b/src/ucm/parser.c index e57e208a8..8af232d27 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1873,7 +1873,7 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) continue; if (strcmp(id, "Comment") == 0) { - err = parse_string(n, &uc_mgr->comment); + err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment); if (err < 0) { uc_error("error: failed to get master comment"); return err; From 2b217b7010b7d57848db9c01eb57b5535c332af2 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 6 Oct 2020 10:47:11 +0200 Subject: [PATCH 26/48] ucm: rename once_list to boot_list Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 8 ++++---- src/ucm/parser.c | 6 +++--- src/ucm/ucm_local.h | 2 +- src/ucm/utils.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index 00b417089..49865df8c 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -577,7 +577,7 @@ static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr) { if (!list_empty(&uc_mgr->verb_list)) return 0; - if (!list_empty(&uc_mgr->once_list)) + if (!list_empty(&uc_mgr->boot_list)) return 0; return -ENXIO; } @@ -976,7 +976,7 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, if (mgr == NULL) return -ENOMEM; INIT_LIST_HEAD(&mgr->verb_list); - INIT_LIST_HEAD(&mgr->once_list); + INIT_LIST_HEAD(&mgr->boot_list); INIT_LIST_HEAD(&mgr->default_list); INIT_LIST_HEAD(&mgr->value_list); INIT_LIST_HEAD(&mgr->active_modifiers); @@ -1878,10 +1878,10 @@ static int set_boot_user(snd_use_case_mgr_t *uc_mgr, uc_error("error: wrong value for _boot (%s)", value); return -EINVAL; } - err = execute_sequence(uc_mgr, &uc_mgr->once_list, + err = execute_sequence(uc_mgr, &uc_mgr->boot_list, &uc_mgr->value_list, NULL, NULL); if (err < 0) { - uc_error("Unable to execute once sequence"); + uc_error("Unable to execute boot sequence"); return err; } return err; diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 8af232d27..75b78826f 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1746,11 +1746,11 @@ static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) { int err; - if (!list_empty(&uc_mgr->once_list)) { - uc_error("Once list is not empty"); + if (!list_empty(&uc_mgr->boot_list)) { + uc_error("Boot list is not empty"); return -EINVAL; } - err = parse_sequence(uc_mgr, &uc_mgr->once_list, cfg); + err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg); if (err < 0) { uc_error("Unable to parse BootSequence"); return err; diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index dd72e3f55..e564e839c 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -223,7 +223,7 @@ struct snd_use_case_mgr { struct list_head verb_list; /* boot settings - sequence */ - struct list_head once_list; + struct list_head boot_list; /* default settings - sequence */ struct list_head default_list; diff --git a/src/ucm/utils.c b/src/ucm/utils.c index fbced51a2..df6fd4dee 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -681,7 +681,7 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) list_del(&verb->list); free(verb); } - uc_mgr_free_sequence(&uc_mgr->once_list); + uc_mgr_free_sequence(&uc_mgr->boot_list); uc_mgr_free_sequence(&uc_mgr->default_list); uc_mgr_free_value(&uc_mgr->value_list); uc_mgr_free_value(&uc_mgr->variable_list); From 4f90392f07e8822d1984ed990f622ad36022a4a3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 9 Oct 2020 19:57:57 +0200 Subject: [PATCH 27/48] pcm: fix the snd_pcm_plugin_status() avail and delay fields The avail and delay fields in the returned status structure does not reflect the actual hw_ptr/appl_ptr. This change correct this. TODO: Unfortunately, the delay might contain also information about extra hardware / buffering delay which is hidden with this change. Link: https://lore.kernel.org/alsa-devel/d9c1f37e-5c8d-f289-270e-c6cda7a56ce3@axis.com/ Reported-by: Jonas Holmberg Tested-by: Jonas Holmberg Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_plugin.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index ea60eb989..5739cfc2e 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -541,16 +541,20 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_plugin_t *plugin = pcm->private_data; - snd_pcm_sframes_t err; + snd_pcm_sframes_t err, avail; /* sync with the latest hw and appl ptrs */ - snd_pcm_plugin_avail_update(pcm); + avail = snd_pcm_plugin_avail_update(pcm); + if (avail < 0) + return avail; err = snd_pcm_status(plugin->gen.slave, status); if (err < 0) return err; status->appl_ptr = *pcm->appl.ptr; status->hw_ptr = *pcm->hw.ptr; + status->avail = avail; + status->delay = snd_pcm_mmap_delay(pcm); return 0; } From 8580c081c25678d11278efcb61bd15cf44d0a225 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 10:43:44 +0200 Subject: [PATCH 28/48] dlsym: add support for ALSA_PLUGIN_DIR environment variable In some cases, it may be useful to specify the plugin directory using the environment variable. BugLink: https://github.com/alsa-project/alsa-lib/issues/82 Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 55 ++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index 1a60e0dda..8a600dec1 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -43,8 +43,8 @@ struct snd_dlsym_link *snd_dlsym_start = NULL; #endif #ifdef DL_ORIGIN_AVAILABLE -static int snd_libdir_plugin_dir_set = 0; -static char *snd_libdir_origin = NULL; +static int snd_plugin_dir_set = 0; +static char *snd_plugin_dir = NULL; #endif #endif @@ -65,6 +65,22 @@ static inline void snd_dlpath_lock(void) {} static inline void snd_dlpath_unlock(void) {} #endif +static void snd_dlinfo_origin(char *path, size_t path_len) +{ +#ifdef DL_ORIGIN_AVAILABLE + struct link_map *links; + Dl_info info; + char origin[PATH_MAX]; + if (dladdr1(&snd_dlpath, &info, (void**)&links, RTLD_DL_LINKMAP) == 0) + return; + if (dlinfo(links, RTLD_DI_ORIGIN, origin)) + return; + snprintf(path, path_len, "%s/alsa-lib", origin); + if (access(path, X_OK) == 0) + snd_plugin_dir = strdup(path); +#endif +} + /** * * \brief Compose the dynamic path @@ -75,30 +91,19 @@ static inline void snd_dlpath_unlock(void) {} */ int snd_dlpath(char *path, size_t path_len, const char *name) { -#ifdef DL_ORIGIN_AVAILABLE snd_dlpath_lock(); - if (!snd_libdir_plugin_dir_set) { - struct link_map *links; - Dl_info info; - char origin[PATH_MAX]; - if (dladdr1(&snd_dlpath, &info, (void**)&links, RTLD_DL_LINKMAP) == 0) - links = NULL; - if (links != NULL && dlinfo(links, RTLD_DI_ORIGIN, origin) == 0) { - snprintf(path, path_len, "%s/alsa-lib", origin); - if (access(path, X_OK) == 0) - snd_libdir_origin = strdup(origin); + if (!snd_plugin_dir_set) { + const char *env = getenv("ALSA_PLUGIN_DIR"); + if (env) { + snd_plugin_dir = strdup(env); + } else { + snd_dlinfo_origin(path, path_len); } - snd_libdir_plugin_dir_set = 1; - } - if (snd_libdir_origin) { - snprintf(path, path_len, "%s/alsa-lib/%s", snd_libdir_origin, name); - } else { - snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name); + snd_plugin_dir_set = 1; } + snprintf(path, path_len, "%s/%s", + snd_plugin_dir ? snd_plugin_dir : ALSA_PLUGIN_DIR, name); snd_dlpath_unlock(); -#else - snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name); -#endif return 0; } @@ -450,9 +455,9 @@ void snd_dlobj_cache_cleanup(void) snd_dlobj_unlock(); #ifdef DL_ORIGIN_AVAILABLE snd_dlpath_lock(); - snd_libdir_plugin_dir_set = 0; - free(snd_libdir_origin); - snd_libdir_origin = NULL; + snd_plugin_dir_set = 0; + free(snd_plugin_dir); + snd_plugin_dir = NULL; snd_dlpath_unlock(); #endif } From 2a204a5412ee956ede792a6872ff3d0516d0f0df Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 11:32:27 +0200 Subject: [PATCH 29/48] dlmisc, pcm: export the old symbols (for -flto) All old symbols must be visible (exported) for -flto. BugLink: https://github.com/alsa-project/alsa-lib/issues/56 Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 2 +- src/pcm/pcm.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index 8a600dec1..0362b9d1c 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -177,7 +177,7 @@ void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen) } #ifndef DOXYGEN -void *INTERNAL(snd_dlopen_old)(const char *name, int mode) +EXPORT_SYMBOL void *INTERNAL(snd_dlopen_old)(const char *name, int mode) { return INTERNAL(snd_dlopen)(name, mode, NULL, 0); } diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 06a48f4c3..24030b318 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -7834,7 +7834,7 @@ void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave) #endif /* USE_VERSIONED_SYMBOLS */ #define __P_OLD_GET(pfx, name, val_type, ret_type) \ -ret_type pfx##name(const snd_pcm_hw_params_t *params) \ +EXPORT_SYMBOL ret_type pfx##name(const snd_pcm_hw_params_t *params) \ { \ val_type val; \ if (INTERNAL(name)(params, &val) < 0) \ @@ -7843,7 +7843,7 @@ ret_type pfx##name(const snd_pcm_hw_params_t *params) \ } #define __P_OLD_GET1(pfx, name, val_type, ret_type) \ -ret_type pfx##name(const snd_pcm_hw_params_t *params, int *dir) \ +EXPORT_SYMBOL ret_type pfx##name(const snd_pcm_hw_params_t *params, int *dir) \ { \ val_type val; \ if (INTERNAL(name)(params, &val, dir) < 0) \ @@ -7885,7 +7885,7 @@ __OLD_GET(snd_pcm_hw_params_get_buffer_size_max, snd_pcm_uframes_t, snd_pcm_ufra __OLD_GET1(snd_pcm_hw_params_get_tick_time_max, unsigned int, unsigned int); #define __P_OLD_NEAR(pfx, name, ret_type) \ -ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \ +EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \ { \ if (INTERNAL(name)(pcm, params, &val) < 0) \ return 0; \ @@ -7893,7 +7893,7 @@ ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \ } #define __P_OLD_NEAR1(pfx, name, ret_type) \ -ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \ +EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \ { \ if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ return 0; \ @@ -7913,7 +7913,7 @@ __OLD_NEAR(snd_pcm_hw_params_set_buffer_size_near, snd_pcm_uframes_t); __OLD_NEAR1(snd_pcm_hw_params_set_tick_time_near, unsigned int); #define __P_OLD_SET_FL(pfx, name, ret_type) \ -ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \ +EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \ { \ ret_type val; \ if (INTERNAL(name)(pcm, params, &val) < 0) \ @@ -7922,7 +7922,7 @@ ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \ } #define __P_OLD_SET_FL1(pfx, name, ret_type) \ -ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir) \ +EXPORT_SYMBOL ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir) \ { \ ret_type val; \ if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ @@ -7958,7 +7958,7 @@ __OLD_SET_FL(snd_pcm_hw_params_set_buffer_size_last, snd_pcm_uframes_t); __OLD_SET_FL1(snd_pcm_hw_params_set_tick_time_last, unsigned int); #define __P_OLD_GET_SW(pfx, name, ret_type) \ -ret_type pfx##name(snd_pcm_sw_params_t *params) \ +EXPORT_SYMBOL ret_type pfx##name(snd_pcm_sw_params_t *params) \ { \ ret_type val; \ if (INTERNAL(name)(params, &val) < 0) \ From aa89ad93623fc97fed6f99370a97c9c3eee1d6fd Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 16:51:21 +0200 Subject: [PATCH 30/48] dlsym: use the only alsa plugins directory for the internal modules The commit b2a4272ecb40d84556d8e043d0b6e89439acbc33 introduced a slightly different behaviour for ALSA_PLUGIN_DIR. The fallback causes that the alsa libraries are searched in all library directories. It was never intended to do the system wide library lookups for internal modules. Fixes: b2a4272ecb40 ("snd_dlopen: do not use absolute plugin path for snd_dlopen() calls") Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index 0362b9d1c..c9517c551 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -147,31 +147,20 @@ void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen) * via ld.so.conf. */ void *handle = NULL; - const char *filename = NULL; + const char *filename = name; char path[PATH_MAX]; if (name && name[0] != '/') { - if (snd_dlpath(path, sizeof(path), name) == 0) { + if (snd_dlpath(path, sizeof(path), name) == 0) filename = path; - handle = dlopen(filename, mode); - if (!handle) { - /* if the filename exists and cannot be opened */ - /* return immediately */ - if (access(filename, X_OK) == 0) - goto errpath; - } - } - } - if (!handle) { - filename = name; - handle = dlopen(name, mode); - if (!handle) - goto errpath; } + handle = dlopen(filename, mode); + if (!handle) + goto errpath; return handle; errpath: if (errbuf) - snprintf(errbuf, errbuflen, "%s: %s", filename, dlerror()); + snprintf(errbuf, errbuflen, "%s", dlerror()); #endif return NULL; } From a6c8ac0c85ca1b16684a687c7000c73aa38b7776 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 19:28:29 +0200 Subject: [PATCH 31/48] pcm: meter / s16 - add protection for the maximum copied frames The rewind or forward may cause the stream pointer change. Although this patch does not fix the real meter update issue, it breaks the possible big loops when the stream pointers are desynced with the meters. It does not make sense to copy more samples than the pcm buffer contains. Link: https://lore.kernel.org/alsa-devel/f56d6a67-014a-e562-c253-830c0ec03717@ivitera.com/ Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_meter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 20b41876d..2dcf8e45b 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -79,6 +79,8 @@ static void snd_pcm_meter_add_frames(snd_pcm_t *pcm, snd_pcm_uframes_t frames) { snd_pcm_meter_t *meter = pcm->private_data; + if (frames > pcm->buffer_size) + frames = pcm->buffer_size; while (frames > 0) { snd_pcm_uframes_t n = frames; snd_pcm_uframes_t dst_offset = ptr % meter->buf_size; @@ -1100,6 +1102,8 @@ static void s16_update(snd_pcm_scope_t *scope) size = meter->now - s16->old; if (size < 0) size += spcm->boundary; + if (size > (snd_pcm_sframes_t)s16->pcm->buffer_size) + size = s16->pcm->buffer_size; offset = s16->old % meter->buf_size; while (size > 0) { snd_pcm_uframes_t frames = size; From 6d06fcc285babd19afba3d3c14206f17e1b2583b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 20:10:49 +0200 Subject: [PATCH 32/48] pcm: introduce pcm_frame_diff and pcm_frame_diff2 helpers Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_dmix.c | 33 +++++++-------------------------- src/pcm/pcm_dshare.c | 11 ++--------- src/pcm/pcm_dsnoop.c | 6 +----- src/pcm/pcm_local.h | 20 ++++++++++++++++++++ 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 8bce7aca8..bcac273b8 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -319,18 +319,13 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) /* check the available size in the local buffer * last_appl_ptr keeps the last updated position */ - size = dmix->appl_ptr - dmix->last_appl_ptr; + size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary); if (! size) return; - if (size >= pcm->boundary / 2) - size = pcm->boundary - size; /* the slave_app_ptr can be far behind the slave_hw_ptr */ /* reduce mixing and errors here - just skip not catched writes */ - if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr) - slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; - else - slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr); + slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, dmix->slave_boundary); if (slave_size > dmix->slave_buffer_size) { transfer = dmix->slave_buffer_size - slave_size; if (transfer > size) @@ -339,11 +334,9 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) dmix->last_appl_ptr %= pcm->boundary; dmix->slave_appl_ptr += transfer; dmix->slave_appl_ptr %= dmix->slave_boundary; - size = dmix->appl_ptr - dmix->last_appl_ptr; + size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary); if (! size) return; - if (size >= pcm->boundary / 2) - size = pcm->boundary - size; } /* check the available size in the slave PCM buffer */ @@ -355,10 +348,7 @@ static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) slave_hw_ptr += dmix->slave_buffer_size; if (slave_hw_ptr >= dmix->slave_boundary) slave_hw_ptr -= dmix->slave_boundary; - if (slave_hw_ptr < dmix->slave_appl_ptr) - slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr); - else - slave_size = slave_hw_ptr - dmix->slave_appl_ptr; + slave_size = pcm_frame_diff(slave_hw_ptr, dmix->slave_appl_ptr, dmix->slave_boundary); if (slave_size < size) size = slave_size; if (! size) @@ -726,10 +716,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f * So they can be remixed. */ - if (dmix->last_appl_ptr < dmix->appl_ptr) - size = dmix->appl_ptr - dmix->last_appl_ptr; - else - size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr); + size = pcm_frames_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary); if (frames < size) size = frames; snd_pcm_mmap_appl_backward(pcm, size); @@ -741,16 +728,10 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f /* Always at this point last_appl_ptr == appl_ptr * So (appl_ptr - hw_ptr) indicates the frames which can be remixed */ - if (dmix->hw_ptr < dmix->appl_ptr) - size = dmix->appl_ptr - dmix->hw_ptr; - else - size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr); + size = pcm_frames_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary); if (size > frames) size = frames; - if (dmix->slave_hw_ptr < dmix->slave_appl_ptr) - slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr; - else - slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr); + slave_size = pcm_frames_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary); if (slave_size < size) size = slave_size; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 6a99452b8..88fb8bf96 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -123,10 +123,7 @@ static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) slave_hw_ptr += dshare->slave_buffer_size; if (slave_hw_ptr >= dshare->slave_boundary) slave_hw_ptr -= dshare->slave_boundary; - if (slave_hw_ptr < dshare->slave_appl_ptr) - slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr); - else - slave_size = slave_hw_ptr - dshare->slave_appl_ptr; + slave_size = pcm_frames_diff(slave_hw_ptr, dshare->slave_appl_ptr, dshare->slave_boundary); if (slave_size < size) size = slave_size; if (! size) @@ -169,17 +166,13 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p old_slave_hw_ptr = dshare->slave_hw_ptr; dshare->slave_hw_ptr = slave_hw_ptr; - diff = slave_hw_ptr - old_slave_hw_ptr; + diff = pcm_frames_diff(slave_hw_ptr, old_slave_hw_ptr, dshare->slave_boundary); if (diff == 0) /* fast path */ return 0; if (dshare->state != SND_PCM_STATE_RUNNING && dshare->state != SND_PCM_STATE_DRAINING) /* not really started yet - don't update hw_ptr */ return 0; - if (diff < 0) { - slave_hw_ptr += dshare->slave_boundary; - diff = slave_hw_ptr - old_slave_hw_ptr; - } dshare->hw_ptr += diff; dshare->hw_ptr %= pcm->boundary; // printf("sync ptr diff = %li\n", diff); diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 7904314cf..bafb6ddd5 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -152,13 +152,9 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) old_slave_hw_ptr = dsnoop->slave_hw_ptr; snoop_timestamp(pcm); slave_hw_ptr = dsnoop->slave_hw_ptr; - diff = slave_hw_ptr - old_slave_hw_ptr; + diff = pcm_frames_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary); if (diff == 0) /* fast path */ return 0; - if (diff < 0) { - slave_hw_ptr += dsnoop->slave_boundary; - diff = slave_hw_ptr - old_slave_hw_ptr; - } snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff); dsnoop->hw_ptr += diff; dsnoop->hw_ptr %= pcm->boundary; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index aae58ed38..fe77e50de 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -1170,6 +1170,26 @@ static inline void sw_set_period_event(snd_pcm_sw_params_t *params, int val) #define PCMINABORT(pcm) (((pcm)->mode & SND_PCM_ABORT) != 0) +static inline snd_pcm_sframes_t pcm_frame_diff(snd_pcm_uframes_t ptr1, + snd_pcm_uframes_t ptr2, + snd_pcm_uframes_t boundary) +{ + if (ptr1 < ptr2) + return ptr1 + (boundary - ptr2); + else + return ptr1 - ptr2; +} + +static inline snd_pcm_sframes_t pcm_frame_diff2(snd_pcm_uframes_t ptr1, + snd_pcm_uframes_t ptr2, + snd_pcm_uframes_t boundary) +{ + snd_pcm_sframes_t r = ptr1 - ptr2; + if (r >= (snd_pcm_sframes_t)boundary / 2) + return boundary - r; + return r; +} + #ifdef THREAD_SAFE_API /* * __snd_pcm_lock() and __snd_pcm_unlock() are used to lock/unlock the plugin From ebe2f8b85132757fa8deb3a8e511d5cc06c53c8d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 13 Oct 2020 20:15:04 +0200 Subject: [PATCH 33/48] pcm: dshare - apply the boundary wrap in snd_pcm_dshare_sync_area() BugLink: https://github.com/alsa-project/alsa-lib/issues/84 Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_dshare.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 88fb8bf96..f211c1a0f 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -112,7 +112,7 @@ static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) const snd_pcm_channel_area_t *src_areas, *dst_areas; /* calculate the size to transfer */ - size = dshare->appl_ptr - dshare->last_appl_ptr; + size = pcm_frames_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary); if (! size) return; slave_hw_ptr = dshare->slave_hw_ptr; From 0128af6f5401c5bf766968eca4c7f73ce3f1b130 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 14 Oct 2020 17:55:18 +0200 Subject: [PATCH 34/48] pcm: fix the pcm_frames_diff -> pcm_frame_diff typo BugLink: https://github.com/alsa-project/alsa-lib/issues/85 Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_dmix.c | 6 +++--- src/pcm/pcm_dshare.c | 6 +++--- src/pcm/pcm_dsnoop.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index bcac273b8..5b7472d90 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -716,7 +716,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f * So they can be remixed. */ - size = pcm_frames_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary); + size = pcm_frame_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary); if (frames < size) size = frames; snd_pcm_mmap_appl_backward(pcm, size); @@ -728,10 +728,10 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f /* Always at this point last_appl_ptr == appl_ptr * So (appl_ptr - hw_ptr) indicates the frames which can be remixed */ - size = pcm_frames_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary); + size = pcm_frame_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary); if (size > frames) size = frames; - slave_size = pcm_frames_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary); + slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary); if (slave_size < size) size = slave_size; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index f211c1a0f..8a6725729 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -112,7 +112,7 @@ static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) const snd_pcm_channel_area_t *src_areas, *dst_areas; /* calculate the size to transfer */ - size = pcm_frames_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary); + size = pcm_frame_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary); if (! size) return; slave_hw_ptr = dshare->slave_hw_ptr; @@ -123,7 +123,7 @@ static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) slave_hw_ptr += dshare->slave_buffer_size; if (slave_hw_ptr >= dshare->slave_boundary) slave_hw_ptr -= dshare->slave_boundary; - slave_size = pcm_frames_diff(slave_hw_ptr, dshare->slave_appl_ptr, dshare->slave_boundary); + slave_size = pcm_frame_diff(slave_hw_ptr, dshare->slave_appl_ptr, dshare->slave_boundary); if (slave_size < size) size = slave_size; if (! size) @@ -166,7 +166,7 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p old_slave_hw_ptr = dshare->slave_hw_ptr; dshare->slave_hw_ptr = slave_hw_ptr; - diff = pcm_frames_diff(slave_hw_ptr, old_slave_hw_ptr, dshare->slave_boundary); + diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dshare->slave_boundary); if (diff == 0) /* fast path */ return 0; if (dshare->state != SND_PCM_STATE_RUNNING && diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index bafb6ddd5..c6e8cd279 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -152,7 +152,7 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) old_slave_hw_ptr = dsnoop->slave_hw_ptr; snoop_timestamp(pcm); slave_hw_ptr = dsnoop->slave_hw_ptr; - diff = pcm_frames_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary); + diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary); if (diff == 0) /* fast path */ return 0; snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff); From e191b231c5ca201e137a4cbae0669a5f9713592a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 15 Oct 2020 11:56:03 +0200 Subject: [PATCH 35/48] pcm: file plugin - implement safe_write The syscalls may return EINTR when a signal is handled. Implement safe_write() function which does simple write retry. Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_file.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index a02b2dc01..7709a5549 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -100,6 +100,21 @@ typedef struct { #define TO_LE16(x) bswap_16(x) #endif +static ssize_t safe_write(int fd, const void *buf, size_t len) +{ + while (1) { + ssize_t r = write(fd, buf, len); + if (r < 0) { + if (errno == EINTR) + continue; + if (errno == EPIPE) + return -EIO; + return -errno; + } + return r; + } +} + static int snd_pcm_file_append_value(char **string_p, char **index_ch_p, int *len_p, const char *value) { @@ -339,15 +354,15 @@ static int write_wav_header(snd_pcm_t *pcm) setup_wav_header(pcm, &file->wav_header); - res = write(file->fd, header, sizeof(header)); + res = safe_write(file->fd, header, sizeof(header)); if (res != sizeof(header)) goto write_error; - res = write(file->fd, &file->wav_header, sizeof(file->wav_header)); + res = safe_write(file->fd, &file->wav_header, sizeof(file->wav_header)); if (res != sizeof(file->wav_header)) goto write_error; - res = write(file->fd, header2, sizeof(header2)); + res = safe_write(file->fd, header2, sizeof(header2)); if (res != sizeof(header2)) goto write_error; @@ -381,7 +396,7 @@ static void fixup_wav_header(snd_pcm_t *pcm) len = (file->filelen + 0x24) > 0x7fffffff ? 0x7fffffff : (int)(file->filelen + 0x24); len = TO_LE32(len); - ret = write(file->fd, &len, 4); + ret = safe_write(file->fd, &len, 4); if (ret < 0) return; } @@ -390,7 +405,7 @@ static void fixup_wav_header(snd_pcm_t *pcm) len = file->filelen > 0x7fffffff ? 0x7fffffff : (int)file->filelen; len = TO_LE32(len); - ret = write(file->fd, &len, 4); + ret = safe_write(file->fd, &len, 4); if (ret < 0) return; } @@ -421,9 +436,8 @@ static int snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes) size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes; if (n > cont) n = cont; - err = write(file->fd, file->wbuf + file->file_ptr_bytes, n); + err = safe_write(file->fd, file->wbuf + file->file_ptr_bytes, n); if (err < 0) { - err = -errno; file->wbuf_used_bytes = 0; file->file_ptr_bytes = 0; SYSERR("%s write failed, file data may be corrupt", file->fname); From cebe0fe0f9966eb1663d0330576ed2e87b904e92 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 15 Oct 2020 19:13:10 +0200 Subject: [PATCH 36/48] tplg: fix the unaligned_get32/put32 helpers for big endian Signed-off-by: Jaroslav Kysela --- src/topology/tplg_local.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index d553117e2..1cb8b694f 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -16,6 +16,7 @@ #include "local.h" #include "list.h" +#include "bswap.h" #include "topology.h" #include @@ -233,15 +234,21 @@ struct tplg_table { extern struct tplg_table tplg_table[]; extern unsigned int tplg_table_items; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_INT__ == 4 +#if __SIZEOF_INT__ == 4 static inline unsigned int unaligned_get32(void *src) { unsigned int ret; memcpy(&ret, src, sizeof(ret)); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + ret = bswap_32(ret); +#endif return ret; } static inline void unaligned_put32(void *dst, unsigned int val) { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val = bswap_32(val); +#endif memcpy(dst, &val, sizeof(val)); } #endif From d77fb4731886ff1244e815a05b2be6d261382cbe Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 19 Oct 2020 10:42:27 +0200 Subject: [PATCH 37/48] ucm: handle correctly Linked configuration BugLink: https://github.com/alsa-project/alsa-ucm-conf/issues/54 Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ucm/main.c b/src/ucm/main.c index 49865df8c..3871d5aab 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -41,6 +41,12 @@ * misc */ +static int get_value(snd_use_case_mgr_t *uc_mgr, + const char *identifier, + char **value, + const char *mod_dev_name, + const char *verb_name, + int exact); static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, struct list_head *value_list, const char *identifier); static int get_value3(snd_use_case_mgr_t *uc_mgr, @@ -575,6 +581,17 @@ static int import_master_config(snd_use_case_mgr_t *uc_mgr) */ static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr) { + int err; + char *value; + + err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1); + if (err >= 0) { + err = strcasecmp(value, "true") == 0 || + strcmp(value, "1") == 0; + free(value); + if (err) + return 0; + } if (!list_empty(&uc_mgr->verb_list)) return 0; if (!list_empty(&uc_mgr->boot_list)) From 5c1cb568ec76c5f9acb11ef092d65f05cf748940 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 19 Oct 2020 11:02:29 +0200 Subject: [PATCH 38/48] topology: save_config - fix the error path handling Signed-off-by: Jaroslav Kysela --- src/topology/save.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topology/save.c b/src/topology/save.c index 56250af30..c7a5a8013 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -395,9 +395,9 @@ static int save_config(struct tplg_buf *dst, int level, const char *delim, snd_c err = tplg_save_quoted(dst, id); } else { err = tplg_save_string(dst, id, 1); - if (err < 0) - return err; } + if (err < 0) + return err; } else { delim = ""; } From e91b1c0670de7fbcae2b957b6117de38ddbea87b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 19 Oct 2020 11:17:21 +0200 Subject: [PATCH 39/48] topology: straight printf and error path fixes Signed-off-by: Jaroslav Kysela --- src/topology/ctl.c | 4 ++-- src/topology/dapm.c | 2 +- src/topology/data.c | 22 ++++++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index a38399631..dd05424d3 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -879,9 +879,9 @@ int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && mc->max > 0) err = tplg_save_printf(dst, pfx, "\tmax %u\n", mc->max); if (err >= 0 && mc->invert > 0) - err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max); + err = tplg_save_printf(dst, pfx, "\tinvert 1\n"); if (err >= 0 && mc->invert > 0) - err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max); + err = tplg_save_printf(dst, pfx, "\tinvert 1\n"); if (err >= 0) err = tplg_save_ops(tplg, &mc->hdr, dst, pfx2); if (err >= 0) diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 46f2f8b3d..92dc01aa8 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -483,7 +483,7 @@ int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, } if (first) { first = 0; - err = tplg_save_printf(dst, pfx, "\t\tlines [\n", elem->index); + err = tplg_save_printf(dst, pfx, "\t\tlines [\n"); if (err < 0) return err; } diff --git a/src/topology/data.c b/src/topology/data.c index 3585af309..c2931bd2b 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -930,6 +930,8 @@ static int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples, err = tplg_save_printf(dst, pfx, "\t'%s' ", tuple->token); } + if (err < 0) + return err; switch (set->type) { case SND_SOC_TPLG_TUPLE_TYPE_UUID: err = tplg_save_printf(dst, NULL, "'" UUID_FORMAT "'\n", @@ -1276,9 +1278,9 @@ int tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, elem->id, index, ref->id); } else { err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id); - if (err < 0) - return err; } + if (err < 0) + return err; index++; } if (count > 1) { @@ -1612,7 +1614,7 @@ int tplg_decode_manifest_data(snd_tplg_t *tplg, if (!elem) return -ENOMEM; - tplg_log(tplg, 'D', pos, "manifest: private size %d", size); + tplg_log(tplg, 'D', pos, "manifest: private size %zd", size); return tplg_add_data(tplg, elem, bin, size); } @@ -1672,7 +1674,7 @@ static int tplg_verify_tuple_set(snd_tplg_t *tplg, size_t pos, va = bin; if (size < sizeof(*va) || size < va->size) { - tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %d", size); + tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %zd", size); return -EINVAL; } @@ -1719,7 +1721,7 @@ static int tplg_decode_tuple_set(snd_tplg_t *tplg, va = bin; if (size < sizeof(*va) || size < va->size) { - SNDERR("tuples: wrong size %d", size); + SNDERR("tuples: wrong size %zd", size); return -EINVAL; } @@ -1806,14 +1808,14 @@ static int tplg_verify_tuples(snd_tplg_t *tplg, size_t pos, int err; if (size < sizeof(*va)) { - tplg_log(tplg, 'A', pos, "tuples: small size %d", size); + tplg_log(tplg, 'A', pos, "tuples: small size %zd", size); return -EINVAL; } next: va = bin; if (size < sizeof(*va)) { - tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %d", size); + tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %zd", size); return -EINVAL; } @@ -1842,14 +1844,14 @@ static int tplg_decode_tuples(snd_tplg_t *tplg, int err; if (size < sizeof(*va)) { - SNDERR("tuples: small size %d", size); + SNDERR("tuples: small size %zd", size); return -EINVAL; } next: va = bin; if (size < sizeof(*va)) { - SNDERR("tuples: unexpected vendor arry size %d", size); + SNDERR("tuples: unexpected vendor arry size %zd", size); return -EINVAL; } @@ -1894,7 +1896,7 @@ int tplg_add_data(snd_tplg_t *tplg, next: tp = bin; if (off + size < tp->size) { - SNDERR("data: unexpected element size %d", size); + SNDERR("data: unexpected element size %zd", size); return -EINVAL; } From 49bd4b198e867eedb76ce8d1a504309934343532 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 19 Oct 2020 11:45:13 +0200 Subject: [PATCH 40/48] Release v1.2.4 Signed-off-by: Jaroslav Kysela --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 01357fb93..3ac845123 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT(alsa-lib, 1.2.3.2) +AC_INIT(alsa-lib, 1.2.4) AC_CONFIG_SRCDIR([src/control/control.c]) AC_CONFIG_MACRO_DIR([m4]) From ad8c8e5503980295dd8e5e54a6285d2d7e32eb1e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 22 Oct 2020 20:57:32 +0200 Subject: [PATCH 41/48] dlmisc: the snd_plugin_dir_set / snd_plugin_dir must be declared even for \!DL_ORIGIN_AVAILABLE Fixes: 8580c081c2 ("dlsym: add support for ALSA_PLUGIN_DIR environment variable") BugLink: https://github.com/alsa-project/alsa-lib/issues/91 Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index c9517c551..f20eb5937 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -42,11 +42,9 @@ #ifndef PIC struct snd_dlsym_link *snd_dlsym_start = NULL; #endif -#ifdef DL_ORIGIN_AVAILABLE static int snd_plugin_dir_set = 0; static char *snd_plugin_dir = NULL; #endif -#endif #if defined(DL_ORIGIN_AVAILABLE) && defined(HAVE_LIBPTHREAD) static pthread_mutex_t snd_dlpath_mutex = PTHREAD_MUTEX_INITIALIZER; From 1d993b37ab4e0b9b6e6b795d7be84ce97b29e20b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 29 Oct 2020 20:31:19 +0100 Subject: [PATCH 42/48] dlmisc: fix snd_plugin_dir locking for not DL_ORIGIN_AVAILABLE Fixes: 8580c081c2 ("dlsym: add support for ALSA_PLUGIN_DIR environment variable") Signed-off-by: Jaroslav Kysela --- src/dlmisc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dlmisc.c b/src/dlmisc.c index f20eb5937..1dd913564 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -46,7 +46,7 @@ static int snd_plugin_dir_set = 0; static char *snd_plugin_dir = NULL; #endif -#if defined(DL_ORIGIN_AVAILABLE) && defined(HAVE_LIBPTHREAD) +#ifdef HAVE_LIBPTHREAD static pthread_mutex_t snd_dlpath_mutex = PTHREAD_MUTEX_INITIALIZER; static inline void snd_dlpath_lock(void) @@ -440,12 +440,10 @@ void snd_dlobj_cache_cleanup(void) free(c); } snd_dlobj_unlock(); -#ifdef DL_ORIGIN_AVAILABLE snd_dlpath_lock(); snd_plugin_dir_set = 0; free(snd_plugin_dir); snd_plugin_dir = NULL; snd_dlpath_unlock(); -#endif } #endif From 2757191e3b85d491705b31c6ecca2dbd96d26ade Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 29 Oct 2020 20:34:17 +0100 Subject: [PATCH 43/48] pcm: snd_pcm_mmap_readi - fix typo in comment \param size frames to be *read* Signed-off-by: Jaroslav Kysela --- src/pcm/pcm_mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 9600c3831..9cbaae052 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -183,7 +183,7 @@ snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_ufram * \brief Read interleaved frames from a PCM using direct buffer (mmap) * \param pcm PCM handle * \param buffer frames containing buffer - * \param size frames to be written + * \param size frames to be read * \return a positive number of frames actually read otherwise a * negative error code * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) From 39bd0e1a5be3620f9123f7fe72ffa6cb7d463b21 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:29:38 -0600 Subject: [PATCH 44/48] topology: use inclusive language for bclk use bclk_provider for structure fields, 'codec_provider' and 'codec_consumer' for options and modify #defines to use CP and CC suffixes. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/uapi/asoc.h | 11 +++++++---- include/topology.h | 2 +- src/topology/pcm.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/include/sound/uapi/asoc.h b/include/sound/uapi/asoc.h index 4efb4ec42..ceafb1a90 100644 --- a/include/sound/uapi/asoc.h +++ b/include/sound/uapi/asoc.h @@ -169,10 +169,13 @@ #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) /* DAI topology BCLK parameter - * For the backwards capability, by default codec is bclk master + * For the backwards capability, by default codec is bclk provider */ -#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ -#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ +#define SND_SOC_TPLG_BCLK_CP 0 /* codec is bclk provider */ +#define SND_SOC_TPLG_BCLK_CC 1 /* codec is bclk consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_BCLK_CM SND_SOC_TPLG_BCLK_CP +#define SND_SOC_TPLG_BCLK_CS SND_SOC_TPLG_BCLK_CC /* DAI topology FSYNC parameter * For the backwards capability, by default codec is fsync master @@ -335,7 +338,7 @@ struct snd_soc_tplg_hw_config { __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ __le16 reserved; /* for 32bit alignment */ diff --git a/include/topology.h b/include/topology.h index 1f52e66ea..6c9706496 100644 --- a/include/topology.h +++ b/include/topology.h @@ -1028,7 +1028,7 @@ struct snd_tplg_hw_config_template { unsigned char clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - unsigned char bclk_master; /* SND_SOC_TPLG_BCLK_ value */ + unsigned char bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ unsigned char fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ unsigned char mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ unsigned short reserved; /* for 32bit alignment */ diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 191b7a0a9..f05df348f 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -1411,6 +1411,7 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, snd_config_t *n; const char *id, *val = NULL; int ret, ival; + bool provider_legacy; elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG); if (!elem) @@ -1451,8 +1452,15 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, continue; } - if (strcmp(id, "bclk") == 0 || - strcmp(id, "bclk_master") == 0) { + provider_legacy = false; + if (strcmp(id, "bclk_master") == 0) { + SNDERR("deprecated option %s, please use 'bclk'\n", id); + provider_legacy = true; + } + + if (provider_legacy || + strcmp(id, "bclk") == 0) { + if (snd_config_get_string(n, &val) < 0) return -EINVAL; @@ -1462,11 +1470,19 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, */ SNDERR("deprecated bclk value '%s'", val); - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; } else if (!strcmp(val, "codec_slave")) { - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + SNDERR("deprecated bclk value '%s', use 'codec_consumer'", val); + + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; + } else if (!strcmp(val, "codec_consumer")) { + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; } else if (!strcmp(val, "codec_master")) { - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CM; + SNDERR("deprecated bclk value '%s', use 'codec_provider", val); + + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; + } else if (!strcmp(val, "codec_provider")) { + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; } continue; } @@ -1623,10 +1639,10 @@ int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && hc->fmt) err = tplg_save_printf(dst, pfx, "\tformat '%s'\n", get_audio_hw_format_name(hc->fmt)); - if (err >= 0 && hc->bclk_master) + if (err >= 0 && hc->bclk_provider) err = tplg_save_printf(dst, pfx, "\tbclk '%s'\n", - hc->bclk_master == SND_SOC_TPLG_BCLK_CS ? - "codec_slave" : "codec_master"); + hc->bclk_provider == SND_SOC_TPLG_BCLK_CC ? + "codec_consumer" : "codec_provider"); if (err >= 0 && hc->bclk_rate) err = tplg_save_printf(dst, pfx, "\tbclk_freq %u\n", hc->bclk_rate); @@ -1791,7 +1807,7 @@ static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg, cfg->clock_gated = tpl->clock_gated; cfg->invert_bclk = tpl->invert_bclk; cfg->invert_fsync = tpl->invert_fsync; - cfg->bclk_master = tpl->bclk_master; + cfg->bclk_provider = tpl->bclk_provider; cfg->fsync_master = tpl->fsync_master; cfg->mclk_direction = tpl->mclk_direction; cfg->reserved = tpl->reserved; @@ -2174,7 +2190,7 @@ int tplg_decode_link(snd_tplg_t *tplg, hw->clock_gated = link->hw_config[i].clock_gated; hw->invert_bclk = link->hw_config[i].invert_bclk; hw->invert_fsync = link->hw_config[i].invert_fsync; - hw->bclk_master = link->hw_config[i].bclk_master; + hw->bclk_provider = link->hw_config[i].bclk_provider; hw->fsync_master = link->hw_config[i].fsync_master; hw->mclk_direction = link->hw_config[i].mclk_direction; hw->mclk_rate = link->hw_config[i].mclk_rate; From 706192341d1d0bbb906d690b227b9dee5c1fc4b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:29:39 -0600 Subject: [PATCH 45/48] topology: use inclusive language for fsync use fsync_provider for structure fields, 'codec_provider' and 'codec_consumer' for options and modify #defines to use CP and CC suffixes. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/uapi/asoc.h | 11 +++++++---- include/topology.h | 2 +- src/topology/pcm.c | 37 ++++++++++++++++++++++++++----------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/include/sound/uapi/asoc.h b/include/sound/uapi/asoc.h index ceafb1a90..f32c56972 100644 --- a/include/sound/uapi/asoc.h +++ b/include/sound/uapi/asoc.h @@ -178,10 +178,13 @@ #define SND_SOC_TPLG_BCLK_CS SND_SOC_TPLG_BCLK_CC /* DAI topology FSYNC parameter - * For the backwards capability, by default codec is fsync master + * For the backwards capability, by default codec is fsync provider */ -#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ -#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ +#define SND_SOC_TPLG_FSYNC_CP 0 /* codec is fsync provider */ +#define SND_SOC_TPLG_FSYNC_CC 1 /* codec is fsync consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_FSYNC_CM SND_SOC_TPLG_FSYNC_CP +#define SND_SOC_TPLG_FSYNC_CS SND_SOC_TPLG_FSYNC_CC /* * Block Header. @@ -339,7 +342,7 @@ struct snd_soc_tplg_hw_config { __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ - __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + __u8 fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ __le16 reserved; /* for 32bit alignment */ __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/include/topology.h b/include/topology.h index 6c9706496..4ade20df0 100644 --- a/include/topology.h +++ b/include/topology.h @@ -1029,7 +1029,7 @@ struct snd_tplg_hw_config_template { unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ unsigned char bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ - unsigned char fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + unsigned char fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */ unsigned char mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ unsigned short reserved; /* for 32bit alignment */ unsigned int mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/src/topology/pcm.c b/src/topology/pcm.c index f05df348f..c8f418621 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -1504,8 +1504,15 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, continue; } - if (strcmp(id, "fsync") == 0 || - strcmp(id, "fsync_master") == 0) { + provider_legacy = false; + if (strcmp(id, "fsync_master") == 0) { + SNDERR("deprecated option %s, please use 'fsync'\n", id); + provider_legacy = true; + } + + if (provider_legacy || + strcmp(id, "fsync") == 0) { + if (snd_config_get_string(n, &val) < 0) return -EINVAL; @@ -1515,11 +1522,19 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, */ SNDERR("deprecated fsync value '%s'", val); - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; } else if (!strcmp(val, "codec_slave")) { - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + SNDERR("deprecated fsync value '%s', use 'codec_consumer'", val); + + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; + } else if (!strcmp(val, "codec_consumer")) { + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; } else if (!strcmp(val, "codec_master")) { - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CM; + SNDERR("deprecated fsync value '%s', use 'codec_provider'", val); + + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP; + } else if (!strcmp(val, "codec_provider")) { + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP; } continue; } @@ -1648,10 +1663,10 @@ int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED, hc->bclk_rate); if (err >= 0 && hc->invert_bclk) err = tplg_save_printf(dst, pfx, "\tbclk_invert 1\n"); - if (err >= 0 && hc->fsync_master) - err = tplg_save_printf(dst, pfx, "\tfsync_master '%s'\n", - hc->fsync_master == SND_SOC_TPLG_FSYNC_CS ? - "codec_slave" : "codec_master"); + if (err >= 0 && hc->fsync_provider) + err = tplg_save_printf(dst, pfx, "\tfsync_provider '%s'\n", + hc->fsync_provider == SND_SOC_TPLG_FSYNC_CC ? + "codec_consumer" : "codec_provider"); if (err >= 0 && hc->fsync_rate) err = tplg_save_printf(dst, pfx, "\tfsync_freq %u\n", hc->fsync_rate); @@ -1808,7 +1823,7 @@ static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg, cfg->invert_bclk = tpl->invert_bclk; cfg->invert_fsync = tpl->invert_fsync; cfg->bclk_provider = tpl->bclk_provider; - cfg->fsync_master = tpl->fsync_master; + cfg->fsync_provider = tpl->fsync_provider; cfg->mclk_direction = tpl->mclk_direction; cfg->reserved = tpl->reserved; cfg->mclk_rate = tpl->mclk_rate; @@ -2191,7 +2206,7 @@ int tplg_decode_link(snd_tplg_t *tplg, hw->invert_bclk = link->hw_config[i].invert_bclk; hw->invert_fsync = link->hw_config[i].invert_fsync; hw->bclk_provider = link->hw_config[i].bclk_provider; - hw->fsync_master = link->hw_config[i].fsync_master; + hw->fsync_provider = link->hw_config[i].fsync_provider; hw->mclk_direction = link->hw_config[i].mclk_direction; hw->mclk_rate = link->hw_config[i].mclk_rate; hw->bclk_rate = link->hw_config[i].bclk_rate; From e5c350d7bc6f3d45702059c0ae8d32b3603273c1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Nov 2020 10:29:40 -0600 Subject: [PATCH 46/48] topology: use inclusive language in documentation Use codec_provider and codec_consumer for bclk and fsync Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/topology.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/topology.h b/include/topology.h index 4ade20df0..d1feee4d9 100644 --- a/include/topology.h +++ b/include/topology.h @@ -658,8 +658,8 @@ extern "C" { * * id "1" # used for binding to the config * format "I2S" # physical audio format. - * bclk "master" # Platform is master of bit clock - * fsync "slave" # Platform is slave of fsync + * bclk "codec_provider" # Codec provides the bit clock + * fsync "codec_consumer" # Codec follows the fsync * } * * From 7d36895225d09ae26868997382445cc7ad2e9513 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Wed, 4 Nov 2020 14:49:56 +0100 Subject: [PATCH 47/48] pcm: set the snd_pcm_ioplug_status() tstamp field Set the status tstamp field so that it can be accessed with snd_pcm_status_get_htstamp(). Signed-off-by: Jonas Holmberg Signed-off-by: Takashi Iwai --- src/pcm/pcm_ioplug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c index a437ca326..9b1b8ac3b 100644 --- a/src/pcm/pcm_ioplug.c +++ b/src/pcm/pcm_ioplug.c @@ -115,6 +115,7 @@ static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) snd_pcm_ioplug_hw_ptr_update(pcm); status->state = io->data->state; status->trigger_tstamp = io->trigger_tstamp; + gettimestamp(&status->tstamp, pcm->tstamp_type); status->avail = snd_pcm_mmap_avail(pcm); status->avail_max = io->avail_max; return 0; From 2a99fd919c6972a28e06d3587410f4c7297a3126 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 29 Jan 2019 20:52:54 +0000 Subject: [PATCH 48/48] topology: ctl: Fix parsing of enum kcontrol texts. Enum kcontrol text value parsing is broken. Fix it. Signed-off-by: Liam Girdwood --- src/topology/ctl.c | 54 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/topology/ctl.c b/src/topology/ctl.c index dd05424d3..a920b6fc3 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -427,6 +427,50 @@ int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED, return err; } +static int parse_enum_text_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_t *cfg, + struct tplg_elem *elem) +{ + struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl; + snd_config_type_t type; + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + type = snd_config_get_type(cfg); + + if (type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound type expected for %s", id); + return -EINVAL; + } + + /* refer to a list of enum texts */ + snd_config_for_each(i, next, cfg) { + const char *val; + int err; + + n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &val) < 0) + continue; + + if (ec->items >= SND_SOC_TPLG_NUM_TEXTS) { + SNDERR("error: exceed max hw configs for link %s", id); + return -EINVAL; + } + + ec->items++; + err = tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val); + if (err < 0) + return err; + + tplg_dbg("\t%s: %s\n", id, val); + } + + return 0; +} + /* Parse Control Bytes */ int tplg_parse_control_bytes(snd_tplg_t *tplg, snd_config_t *cfg, @@ -605,7 +649,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, struct tplg_elem *elem; snd_config_iterator_t i, next; snd_config_t *n; - const char *id, *val = NULL; + const char *id; int err, j; bool access_set = false; @@ -639,11 +683,9 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, continue; if (strcmp(id, "texts") == 0) { - if (snd_config_get_string(n, &val) < 0) - return -EINVAL; - - tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val); - tplg_dbg("\t%s: %s", id, val); + err = parse_enum_text_refs(tplg, n, elem); + if (err < 0) + return err; continue; }