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. 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]) diff --git a/include/control.h b/include/control.h index 02db72d41..8766f4409 100644 --- a/include/control.h +++ b/include/control.h @@ -56,13 +56,127 @@ 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 */ 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 */ @@ -354,11 +468,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); @@ -454,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/include/sound/uapi/asoc.h b/include/sound/uapi/asoc.h index 4efb4ec42..f32c56972 100644 --- a/include/sound/uapi/asoc.h +++ b/include/sound/uapi/asoc.h @@ -169,16 +169,22 @@ #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 + * 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. @@ -335,8 +341,8 @@ 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 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ 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 1f52e66ea..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 * } * * @@ -1028,8 +1028,8 @@ 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 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + unsigned char bclk_provider; /* SND_SOC_TPLG_BCLK_ 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/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) 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 diff --git a/src/control/control.c b/src/control/control.c index e21e8f1d2..08058c067 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -31,32 +31,93 @@ /*! \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 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 - - An element can be identified by userspace applications. Each element has - own identical information. - - 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. + - 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. + 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 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 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 -The type of element set is one of integer, integerr64, boolean, enumerators, +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 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 + +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 @@ -280,6 +341,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 @@ -862,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) { @@ -874,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 @@ -1508,9 +1600,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 +1623,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 +2117,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 +2126,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 +2143,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 +2160,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 +2177,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 +2204,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 +2220,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 +2277,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 @@ -2763,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) { @@ -2777,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) { @@ -2787,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) @@ -2795,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. */ @@ -2807,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, @@ -2820,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) { @@ -2831,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) { @@ -2842,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) { @@ -2854,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) { @@ -2865,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) { @@ -2877,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) { @@ -2888,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) { @@ -2898,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) { @@ -2910,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) { @@ -2921,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) { @@ -2932,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) { @@ -2943,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) { @@ -2954,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) { @@ -2965,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) { @@ -2976,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); @@ -2990,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); @@ -3004,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); @@ -3018,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); @@ -3032,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); @@ -3046,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); @@ -3060,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); @@ -3074,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); @@ -3088,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); @@ -3102,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); @@ -3116,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) { @@ -3129,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); @@ -3140,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); @@ -3152,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); diff --git a/src/dlmisc.c b/src/dlmisc.c index 1a60e0dda..1dd913564 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -42,13 +42,11 @@ #ifndef PIC 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; -#endif +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) @@ -65,6 +63,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 +89,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; } @@ -142,37 +145,26 @@ 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; } #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); } @@ -448,12 +440,10 @@ void snd_dlobj_cache_cleanup(void) free(c); } 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 } #endif 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) \ diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index e9343b19a..5b7472d90 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)); } } @@ -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_frame_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_frame_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_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 6a99452b8..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 = dshare->appl_ptr - dshare->last_appl_ptr; + size = pcm_frame_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary); if (! size) return; slave_hw_ptr = dshare->slave_hw_ptr; @@ -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_frame_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_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 && 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..c6e8cd279 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_frame_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_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); 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; 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 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; 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) 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; } 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/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 90241b631..a920b6fc3 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; @@ -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, @@ -557,7 +601,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]; @@ -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; } @@ -697,7 +739,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 +900,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]; @@ -879,9 +921,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) @@ -1088,11 +1130,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) { @@ -1327,23 +1377,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; - struct snd_tplg_channel_map_template cmt; 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); @@ -1368,18 +1405,17 @@ 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++) { - unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE; + for (i = 0; (unsigned int)i < ec->items; i++) et->texts[i] = ec->texts[i]; - et->values[i] = (int *)&ec->values[j]; - } } - 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; @@ -1421,7 +1457,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..92dc01aa8 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; @@ -482,7 +483,7 @@ int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, char **dst, const char *pf } 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; } @@ -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; @@ -972,8 +973,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/data.c b/src/topology/data.c index 5742b3577..c2931bd2b 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; @@ -929,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", @@ -1014,7 +1017,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 +1088,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 +1159,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 +1245,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; @@ -1275,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) { @@ -1420,7 +1423,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; @@ -1611,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); } @@ -1671,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; } @@ -1718,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; } @@ -1805,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; } @@ -1841,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; } @@ -1893,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; } 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/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 b15b95045..c8f418621 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; @@ -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; @@ -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", @@ -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; @@ -618,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; @@ -648,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; @@ -683,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", @@ -744,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); @@ -758,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); } } @@ -773,19 +778,21 @@ 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; - 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; } /* 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; @@ -793,17 +800,17 @@ 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; } 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, @@ -937,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]; @@ -1074,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]; @@ -1228,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]; @@ -1308,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]; @@ -1404,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) @@ -1444,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; @@ -1455,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; } @@ -1481,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; @@ -1492,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; } @@ -1604,7 +1642,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; @@ -1616,19 +1654,19 @@ 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); 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); @@ -1784,8 +1822,8 @@ 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->fsync_master = tpl->fsync_master; + cfg->bclk_provider = tpl->bclk_provider; + cfg->fsync_provider = tpl->fsync_provider; cfg->mclk_direction = tpl->mclk_direction; cfg->reserved = tpl->reserved; cfg->mclk_rate = tpl->mclk_rate; @@ -2167,8 +2205,8 @@ 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->fsync_master = link->hw_config[i].fsync_master; + hw->bclk_provider = link->hw_config[i].bclk_provider; + 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; diff --git a/src/topology/save.c b/src/topology/save.c index 4ecf86c3a..c7a5a8013 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -19,45 +19,86 @@ #include "tplg_local.h" #define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ +#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[1024], *s; + char *s; size_t n, l, t, pl; + int ret = 0; if (pfx == NULL) pfx = ""; va_start(va, fmt); - n = vsnprintf(buf, sizeof(buf), fmt, va); + n = vsnprintf(dst->printf_buf, dst->printf_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 >= dst->printf_buf_size) { + t = NEXT_CHUNK(n + 1, PRINT_ALLOC_SHIFT); + s = realloc(dst->printf_buf, t); + if (!s) { + ret = -ENOMEM; + goto end; + } + dst->printf_buf = s; + dst->printf_buf_size = t; + va_start(va, fmt); + 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; - return -ENOMEM; + ret = -ENOMEM; + goto end; } } else { - s = *dst; + s = dst->dst; } if (pl > 0) strcpy(s + l, pfx); - strcpy(s + l + pl, buf); - *dst = s; - return 0; + strcpy(s + l + pl, dst->printf_buf); + dst->dst = s; + dst->dst_len = t - 1; +end: + return ret; } int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value) @@ -119,7 +160,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; @@ -131,14 +171,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; @@ -187,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; @@ -241,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; @@ -257,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; @@ -356,9 +395,9 @@ static int save_config(char **dst, int level, const char *delim, snd_config_t *s 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 = ""; } @@ -378,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; @@ -462,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; } @@ -518,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; @@ -528,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; @@ -588,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 507c5450a..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; @@ -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; diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 5ace0d191..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 @@ -200,6 +201,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 +223,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); @@ -225,6 +234,25 @@ struct tplg_table { extern struct tplg_table tplg_table[]; extern unsigned int tplg_table_items; +#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 + #define tplg_log(tplg, type, pos, fmt, args...) do { \ if ((tplg)->verbose) \ tplg_log_((tplg), (type), (pos), (fmt), ##args); \ @@ -335,49 +363,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, @@ -398,7 +426,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); diff --git a/src/ucm/main.c b/src/ucm/main.c index 9e43ac66a..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, @@ -568,6 +574,31 @@ 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) +{ + 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)) + return 0; + return -ENXIO; +} + /** * \brief Universal find - string in a list * \param list List of structures @@ -962,7 +993,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); @@ -981,14 +1012,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; } @@ -1858,10 +1895,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 d034b8598..75b78826f 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) */ @@ -1728,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; @@ -1855,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; @@ -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; 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);