diff --git a/SOURCES/alsa-git.patch b/SOURCES/alsa-git.patch new file mode 100644 index 0000000..c0d6687 --- /dev/null +++ b/SOURCES/alsa-git.patch @@ -0,0 +1,1059 @@ +diff --git a/Makefile.am b/Makefile.am +index c484d4da..ff4c963a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -16,7 +16,7 @@ SUBDIRS += alsalisp + endif + endif + SUBDIRS += test utils +-EXTRA_DIST=ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ ++EXTRA_DIST=README.md ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ + depcomp version MEMORY-LEAK m4/attributes.m4 + AUTOMAKE_OPTIONS=foreign + +diff --git a/include/pcm.h b/include/pcm.h +index 5b078231..e300b951 100644 +--- a/include/pcm.h ++++ b/include/pcm.h +@@ -350,6 +350,20 @@ typedef enum _snd_pcm_tstamp_type { + SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, + } snd_pcm_tstamp_type_t; + ++typedef enum _snd_pcm_audio_tstamp_type { ++ /** ++ * first definition for backwards compatibility only, ++ * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else ++ */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, ++ SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /**< DMA time, reported as per hw_ptr */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /**< link time reported by sample or wallclock counter, reset on startup */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /**< link time reported by sample or wallclock counter, not reset on startup */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /**< link time estimated indirectly */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /**< link time synchronized with system time */ ++ SND_PCM_AUDIO_TSTAMP_TYPE_LAST = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED ++} snd_pcm_audio_tstamp_type_t; ++ + typedef struct _snd_pcm_audio_tstamp_config { + /* 5 of max 16 bits used */ + unsigned int type_requested:4; +diff --git a/include/sound/uapi/asoc.h b/include/sound/uapi/asoc.h +index 4efb4ec4..f32c5697 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 1f52e66e..d1feee4d 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 7df2b4e7..3c943db2 100644 +--- a/src/conf.c ++++ b/src/conf.c +@@ -887,7 +887,7 @@ static inline int get_hexachar(input_t *input) + if (c >= '0' && c <= '9') num |= (c - '0') << 0; + else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 0; + else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 0; +- return c; ++ return num; + } + + static int get_quotedchar(input_t *input) +@@ -1970,11 +1970,14 @@ int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, + SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); + goto _end; + } +- if (get_char(&input) != LOCAL_UNEXPECTED_EOF) { ++ err = get_char(&input); ++ fd = input.current; ++ if (err != LOCAL_UNEXPECTED_EOF) { + SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column); + err = -EINVAL; + goto _end; + } ++ err = 0; + _end: + while (fd->next) { + fd_next = fd->next; +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index 9b64af3c..b1b74b02 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -39,6 +39,7 @@ USB-Audio.pcm.iec958_device { + # "NoiseBlaster 3000" 42 + "USB Sound Blaster HD" 1 + "Xonar U7" 1 ++ "Xonar U7 MKII" 1 + "ASUS XONAR U5" 1 + "XONAR U5" 1 + "XONAR SOUND CARD" 1 +diff --git a/src/confmisc.c b/src/confmisc.c +index eb8218c1..3ce95c7a 100644 +--- a/src/confmisc.c ++++ b/src/confmisc.c +@@ -419,7 +419,6 @@ int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + tmp = realloc(res, len + len1 + 1); + if (tmp == NULL) { + free(ptr); +- free(res); + err = -ENOMEM; + goto __error; + } +@@ -440,8 +439,8 @@ int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, + err = snd_config_get_id(src, &id); + if (err >= 0) + err = snd_config_imake_string(dst, id, res); +- free(res); + __error: ++ free(res); + return err; + } + #ifndef DOC_HIDDEN +diff --git a/src/dlmisc.c b/src/dlmisc.c +index c9517c55..1dd91356 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_plugin_dir_set = 0; + static char *snd_plugin_dir = NULL; + #endif +-#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) +@@ -442,12 +440,10 @@ void snd_dlobj_cache_cleanup(void) + free(c); + } + snd_dlobj_unlock(); +-#ifdef DL_ORIGIN_AVAILABLE + snd_dlpath_lock(); + snd_plugin_dir_set = 0; + free(snd_plugin_dir); + snd_plugin_dir = NULL; + snd_dlpath_unlock(); +-#endif + } + #endif +diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c +index a437ca32..e141b1f9 100644 +--- a/src/pcm/pcm_ioplug.c ++++ b/src/pcm/pcm_ioplug.c +@@ -107,16 +107,35 @@ static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *i + return snd_pcm_channel_info_shm(pcm, info, -1); + } + ++static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) ++{ ++ ioplug_priv_t *io = pcm->private_data; ++ ++ if (io->data->version >= 0x010001 && ++ io->data->callback->delay) ++ return io->data->callback->delay(io->data, delayp); ++ else { ++ snd_pcm_ioplug_hw_ptr_update(pcm); ++ *delayp = snd_pcm_mmap_delay(pcm); ++ } ++ return 0; ++} ++ + static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + { + ioplug_priv_t *io = pcm->private_data; ++ snd_pcm_sframes_t sd; + + memset(status, 0, sizeof(*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; ++ if (snd_pcm_ioplug_delay(pcm, &sd) < 0) ++ sd = snd_pcm_mmap_delay(pcm); ++ status->delay = sd; + return 0; + } + +@@ -132,20 +151,6 @@ static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm) + return 0; + } + +-static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +-{ +- ioplug_priv_t *io = pcm->private_data; +- +- if (io->data->version >= 0x010001 && +- io->data->callback->delay) +- return io->data->callback->delay(io->data, delayp); +- else { +- snd_pcm_ioplug_hw_ptr_update(pcm); +- *delayp = snd_pcm_mmap_hw_avail(pcm); +- } +- return 0; +-} +- + static int snd_pcm_ioplug_reset(snd_pcm_t *pcm) + { + ioplug_priv_t *io = pcm->private_data; +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index fe77e50d..bec5a408 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -444,7 +444,7 @@ static inline int __snd_pcm_start(snd_pcm_t *pcm) + static inline snd_pcm_state_t __snd_pcm_state(snd_pcm_t *pcm) + { + if (!pcm->fast_ops->state) +- return -ENOSYS; ++ return SND_PCM_STATE_OPEN; + return pcm->fast_ops->state(pcm->fast_op_arg); + } + +diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c +index 9600c383..9cbaae05 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_multi.c b/src/pcm/pcm_multi.c +index 53c414d5..5fa09b9b 100644 +--- a/src/pcm/pcm_multi.c ++++ b/src/pcm/pcm_multi.c +@@ -1323,7 +1323,6 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + err = -ENOMEM; + goto _free; + } +- idx = 0; + for (idx = 0; idx < channels_count; ++idx) + channels_sidx[idx] = -1; + idx = 0; +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index 5739cfc2..7ed6f25a 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -142,12 +142,6 @@ static int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) + int err = snd_pcm_delay(plugin->gen.slave, &sd); + if (err < 0) + return err; +- if (pcm->stream == SND_PCM_STREAM_CAPTURE && +- pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && +- pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { +- sd += snd_pcm_mmap_capture_avail(pcm); +- } +- + *delayp = sd; + return 0; + } +@@ -460,101 +454,121 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, + return xfer > 0 ? xfer : err; + } + +-static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) ++static snd_pcm_sframes_t ++snd_pcm_plugin_sync_hw_ptr_capture(snd_pcm_t *pcm, ++ snd_pcm_sframes_t slave_size) + { + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; +- snd_pcm_sframes_t slave_size; ++ const snd_pcm_channel_area_t *areas; ++ snd_pcm_uframes_t xfer, hw_offset, size; + int err; + +- slave_size = snd_pcm_avail_update(slave); ++ xfer = snd_pcm_mmap_capture_avail(pcm); ++ size = pcm->buffer_size - xfer; ++ areas = snd_pcm_mmap_areas(pcm); ++ hw_offset = snd_pcm_mmap_hw_offset(pcm); ++ while (size > 0 && slave_size > 0) { ++ snd_pcm_uframes_t frames = size; ++ snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; ++ const snd_pcm_channel_area_t *slave_areas; ++ snd_pcm_uframes_t slave_offset; ++ snd_pcm_uframes_t slave_frames = ULONG_MAX; ++ snd_pcm_sframes_t result; ++ /* As mentioned in the ALSA API (see pcm/pcm.c:942): ++ * The function #snd_pcm_avail_update() ++ * have to be called before any mmap begin+commit operation. ++ * Otherwise the snd_pcm_areas_copy will not called a second time. ++ * But this is needed, if the ring buffer wrap is reached and ++ * there is more data available. ++ */ ++ slave_size = snd_pcm_avail_update(slave); ++ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ if (result < 0) { ++ err = result; ++ goto error; ++ } ++ if (frames > cont) ++ frames = cont; ++ frames = (plugin->read)(pcm, areas, hw_offset, frames, ++ slave_areas, slave_offset, &slave_frames); ++ result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); ++ if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { ++ snd_pcm_sframes_t res; ++ res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); ++ if (res < 0) { ++ err = res; ++ goto error; ++ } ++ frames -= res; ++ } ++ if (result <= 0) { ++ err = result; ++ goto error; ++ } ++ snd_pcm_mmap_hw_forward(pcm, frames); ++ if (frames == cont) ++ hw_offset = 0; ++ else ++ hw_offset += frames; ++ size -= frames; ++ slave_size -= slave_frames; ++ xfer += frames; ++ } ++ return (snd_pcm_sframes_t)xfer; ++error: ++ return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; ++} ++ ++static snd_pcm_sframes_t snd_pcm_plugin_sync_hw_ptr(snd_pcm_t *pcm, ++ snd_pcm_uframes_t slave_hw_ptr, ++ snd_pcm_sframes_t slave_size) ++{ + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && + pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) +- goto _capture; +- *pcm->hw.ptr = *slave->hw.ptr; ++ return snd_pcm_plugin_sync_hw_ptr_capture(pcm, slave_size); ++ *pcm->hw.ptr = slave_hw_ptr; + return slave_size; +- _capture: +- { +- const snd_pcm_channel_area_t *areas; +- snd_pcm_uframes_t xfer, hw_offset, size; +- +- xfer = snd_pcm_mmap_capture_avail(pcm); +- size = pcm->buffer_size - xfer; +- areas = snd_pcm_mmap_areas(pcm); +- hw_offset = snd_pcm_mmap_hw_offset(pcm); +- while (size > 0 && slave_size > 0) { +- snd_pcm_uframes_t frames = size; +- snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; +- const snd_pcm_channel_area_t *slave_areas; +- snd_pcm_uframes_t slave_offset; +- snd_pcm_uframes_t slave_frames = ULONG_MAX; +- snd_pcm_sframes_t result; +- /* As mentioned in the ALSA API (see pcm/pcm.c:942): +- * The function #snd_pcm_avail_update() +- * have to be called before any mmap begin+commit operation. +- * Otherwise the snd_pcm_areas_copy will not called a second time. +- * But this is needed, if the ring buffer wrap is reached and +- * there is more data available. +- */ +- slave_size = snd_pcm_avail_update(slave); +- result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); +- if (result < 0) { +- err = result; +- goto error; +- } +- if (frames > cont) +- frames = cont; +- frames = (plugin->read)(pcm, areas, hw_offset, frames, +- slave_areas, slave_offset, &slave_frames); +- result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); +- if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { +- snd_pcm_sframes_t res; +- +- res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); +- if (res < 0) { +- err = res; +- goto error; +- } +- frames -= res; +- } +- if (result <= 0) { +- err = result; +- goto error; +- } +- snd_pcm_mmap_hw_forward(pcm, frames); +- if (frames == cont) +- hw_offset = 0; +- else +- hw_offset += frames; +- size -= frames; +- slave_size -= slave_frames; +- xfer += frames; +- } +- return (snd_pcm_sframes_t)xfer; ++} + +- error: +- return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; +- } ++static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) ++{ ++ snd_pcm_plugin_t *plugin = pcm->private_data; ++ snd_pcm_t *slave = plugin->gen.slave; ++ snd_pcm_sframes_t slave_size; ++ ++ slave_size = snd_pcm_avail_update(slave); ++ return snd_pcm_plugin_sync_hw_ptr(pcm, *slave->hw.ptr, slave_size); + } + + 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, avail; +- +- /* sync with the latest hw and appl ptrs */ +- avail = snd_pcm_plugin_avail_update(pcm); +- if (avail < 0) +- return avail; ++ snd_pcm_sframes_t err, diff; + + 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); ++ snd_pcm_plugin_sync_hw_ptr(pcm, status->hw_ptr, status->avail); ++ /* ++ * For capture stream, the situation is more complicated, because ++ * snd_pcm_plugin_avail_update() commits the data to the slave pcm. ++ * It means that the slave appl_ptr is updated. Calculate diff and ++ * update the delay and avail. ++ * ++ * This resolves the data inconsistency for immediate calls: ++ * snd_pcm_avail_update() ++ * snd_pcm_status() ++ */ ++ if (pcm->stream == SND_PCM_STREAM_CAPTURE) { ++ status->appl_ptr = *pcm->appl.ptr; ++ diff = pcm_frame_diff(status->appl_ptr, *pcm->appl.ptr, pcm->boundary); ++ status->avail += diff; ++ status->delay += diff; ++ } else { ++ assert(status->appl_ptr == *pcm->appl.ptr); ++ } + return 0; + } + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 5bf7dbb9..770aafea 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -561,17 +561,16 @@ snd_pcm_rate_read_areas1(snd_pcm_t *pcm, + + static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) + { +- snd_pcm_rate_t *rate = pcm->private_data; +- +- snd_pcm_sframes_t slave_hw_ptr_diff = slave_hw_ptr - rate->last_slave_hw_ptr; ++ snd_pcm_rate_t *rate; ++ snd_pcm_sframes_t slave_hw_ptr_diff; + snd_pcm_sframes_t last_slave_hw_ptr_frac; + + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return; + +- if (slave_hw_ptr_diff < 0) +- slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */ +- else if (slave_hw_ptr_diff == 0) ++ rate = pcm->private_data; ++ slave_hw_ptr_diff = pcm_frame_diff(slave_hw_ptr, rate->last_slave_hw_ptr, rate->gen.slave->boundary); ++ if (slave_hw_ptr_diff == 0) + return; + last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size; + /* While handling fraction part fo slave period, rounded value will be +@@ -612,11 +611,7 @@ static snd_pcm_uframes_t snd_pcm_rate_playback_internal_delay(snd_pcm_t *pcm) + { + snd_pcm_rate_t *rate = pcm->private_data; + +- if (rate->appl_ptr < rate->last_commit_ptr) { +- return rate->appl_ptr - rate->last_commit_ptr + pcm->boundary; +- } else { +- return rate->appl_ptr - rate->last_commit_ptr; +- } ++ return pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); + } + + static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +@@ -637,7 +632,7 @@ static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) + + snd_pcm_rate_playback_internal_delay(pcm); + } else { + *delayp = rate->ops.output_frames(rate->obj, slave_delay) +- + snd_pcm_mmap_capture_hw_avail(pcm); ++ + snd_pcm_mmap_capture_delay(pcm); + } + return 0; + } +@@ -746,7 +741,6 @@ static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate, + if (result < 0) + return result; + __partial: +- xfer = 0; + cont = slave_frames; + if (cont > slave_size) + cont = slave_size; +@@ -846,7 +840,6 @@ static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_of + if (result < 0) + return result; + __partial: +- xfer = 0; + cont = slave_frames; + if (cont > rate->gen.slave->period_size) + cont = rate->gen.slave->period_size; +@@ -928,10 +921,7 @@ static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t app + if (slave_size < 0) + return slave_size; + +- if (appl_ptr < rate->last_commit_ptr) +- xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary; +- else +- xfer = appl_ptr - rate->last_commit_ptr; ++ xfer = pcm_frame_diff(appl_ptr, rate->last_commit_ptr, pcm->boundary); + while (xfer >= pcm->period_size && + (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { + err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size); +@@ -966,29 +956,18 @@ static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, + return size; + } + +-static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) ++static snd_pcm_sframes_t snd_pcm_rate_avail_update_capture(snd_pcm_t *pcm, ++ snd_pcm_sframes_t slave_size) + { + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_t *slave = rate->gen.slave; +- snd_pcm_sframes_t slave_size; +- +- slave_size = snd_pcm_avail_update(slave); +- if (slave_size < 0) +- return slave_size; +- +- if (pcm->stream == SND_PCM_STREAM_CAPTURE) +- goto _capture; +- snd_pcm_rate_sync_hwptr(pcm); +- snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); +- return snd_pcm_mmap_avail(pcm); +- _capture: { + snd_pcm_uframes_t xfer, hw_offset, size; + + xfer = snd_pcm_mmap_capture_avail(pcm); + size = pcm->buffer_size - xfer; + hw_offset = snd_pcm_mmap_hw_offset(pcm); + while (size >= pcm->period_size && +- (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { ++ (snd_pcm_uframes_t)slave_size >= slave->period_size) { + int err = snd_pcm_rate_grab_next_period(pcm, hw_offset); + if (err < 0) + return err; +@@ -996,13 +975,29 @@ static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) + return (snd_pcm_sframes_t)xfer; + xfer += pcm->period_size; + size -= pcm->period_size; +- slave_size -= rate->gen.slave->period_size; ++ slave_size -= slave->period_size; + hw_offset += pcm->period_size; + hw_offset %= pcm->buffer_size; + snd_pcm_mmap_hw_forward(pcm, pcm->period_size); + } + return (snd_pcm_sframes_t)xfer; +- } ++} ++ ++static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) ++{ ++ snd_pcm_rate_t *rate = pcm->private_data; ++ snd_pcm_sframes_t slave_size; ++ ++ slave_size = snd_pcm_avail_update(rate->gen.slave); ++ if (slave_size < 0) ++ return slave_size; ++ ++ if (pcm->stream == SND_PCM_STREAM_CAPTURE) ++ return snd_pcm_rate_avail_update_capture(pcm, slave_size); ++ ++ snd_pcm_rate_sync_hwptr(pcm); ++ snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); ++ return snd_pcm_mmap_avail(pcm); + } + + static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm, +@@ -1060,9 +1055,7 @@ static int snd_pcm_rate_drain(snd_pcm_t *pcm) + sw_params.avail_min = 1; + snd_pcm_sw_params(rate->gen.slave, &sw_params); + +- size = rate->appl_ptr - rate->last_commit_ptr; +- if (size > pcm->boundary) +- size -= pcm->boundary; ++ size = pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); + ofs = rate->last_commit_ptr % pcm->buffer_size; + while (size > 0) { + snd_pcm_uframes_t psize, spsize; +@@ -1164,12 +1157,8 @@ static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max); + } else { +- /* FIXME: Maybe possible to somthing similar to +- * snd_pcm_rate_playback_internal_delay() +- * for the capture case. +- */ + status->delay = rate->ops.output_frames(rate->obj, status->delay) +- + snd_pcm_mmap_capture_hw_avail(pcm); ++ + snd_pcm_mmap_capture_delay(pcm); + status->avail = snd_pcm_mmap_capture_avail(pcm); + status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max); + } +diff --git a/src/rawmidi/rawmidi_virt.c b/src/rawmidi/rawmidi_virt.c +index 2c4c27f5..884b8ff8 100644 +--- a/src/rawmidi/rawmidi_virt.c ++++ b/src/rawmidi/rawmidi_virt.c +@@ -315,7 +315,7 @@ int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + int merge, int mode) + { + int err; +- snd_rawmidi_t *rmidi; ++ snd_rawmidi_t *rmidi = NULL; + snd_rawmidi_virtual_t *virt = NULL; + struct pollfd pfd; + +@@ -392,6 +392,7 @@ int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, + free(*inputp); + if (outputp) + free(*outputp); ++ free(rmidi); + return err; + } + +diff --git a/src/timer/timer_query_hw.c b/src/timer/timer_query_hw.c +index dad228c8..d8bac6e7 100644 +--- a/src/timer/timer_query_hw.c ++++ b/src/timer/timer_query_hw.c +@@ -104,7 +104,7 @@ int snd_timer_query_hw_open(snd_timer_query_t **handle, const char *name, int mo + close(fd); + return -SND_ERROR_INCOMPATIBLE_VERSION; + } +- tmr = (snd_timer_query_t *) calloc(1, sizeof(snd_timer_t)); ++ tmr = (snd_timer_query_t *) calloc(1, sizeof(snd_timer_query_t)); + if (tmr == NULL) { + close(fd); + return -ENOMEM; +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 92dc01aa..f6a84a60 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -836,6 +836,7 @@ int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) + default: + SNDERR("widget %s: invalid type %d for ctl %d", + wt->name, ct->type, i); ++ ret = -EINVAL; + break; + } + +diff --git a/src/topology/data.c b/src/topology/data.c +index c2931bd2..5633cdc3 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -860,7 +860,7 @@ static int parse_tuple_set(snd_config_t *cfg, + } + + if ((type == SND_SOC_TPLG_TUPLE_TYPE_WORD +- && tuple_val > UINT_MAX) ++ /* && tuple_val > UINT_MAX */) + || (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT + && tuple_val > USHRT_MAX) + || (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 191b7a0a..a473b59b 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -1411,6 +1411,7 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + snd_config_t *n; + const char *id, *val = NULL; + int ret, ival; ++ bool provider_legacy; + + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG); + if (!elem) +@@ -1451,8 +1452,15 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + continue; + } + +- if (strcmp(id, "bclk") == 0 || +- strcmp(id, "bclk_master") == 0) { ++ provider_legacy = false; ++ if (strcmp(id, "bclk_master") == 0) { ++ SNDERR("deprecated option %s, please use 'bclk'\n", id); ++ provider_legacy = true; ++ } ++ ++ if (provider_legacy || ++ strcmp(id, "bclk") == 0) { ++ + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; + +@@ -1462,11 +1470,19 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + */ + SNDERR("deprecated bclk value '%s'", val); + +- hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; ++ hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; + } else if (!strcmp(val, "codec_slave")) { +- hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; ++ SNDERR("deprecated bclk value '%s', use 'codec_consumer'", val); ++ ++ hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; ++ } else if (!strcmp(val, "codec_consumer")) { ++ hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; + } else if (!strcmp(val, "codec_master")) { +- hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CM; ++ SNDERR("deprecated bclk value '%s', use 'codec_provider", val); ++ ++ hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; ++ } else if (!strcmp(val, "codec_provider")) { ++ hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; + } + continue; + } +@@ -1488,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; + +@@ -1499,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; + } +@@ -1623,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); +@@ -1791,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; +@@ -1989,7 +2020,7 @@ next: + pt->playback = pcm->playback; + pt->capture = pcm->capture; + pt->compress = pcm->compress; +- tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress", ++ tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress %d", + pt->playback, pt->capture, pt->compress); + pt->num_streams = pcm->num_streams; + pt->flag_mask = pcm->flag_mask; +@@ -2174,8 +2205,8 @@ next: + 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 c7a5a801..fecbc6a5 100644 +--- a/src/topology/save.c ++++ b/src/topology/save.c +@@ -133,6 +133,8 @@ static int tplg_pprint_integer(snd_config_t *n, char **ret) + if (llval < INT_MIN || llval > UINT_MAX) + return snd_config_get_ascii(n, ret); + lval = llval; ++ } else { ++ lval = 0; + } + err = tplg_nice_value_format(buf, sizeof(buf), (unsigned int)lval); + if (err < 0) +@@ -178,29 +180,28 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) + } + if (array <= 0) + qsort(a, count, sizeof(a[0]), _compar); +- if (snd_config_make_compound(&dst, id, count == 1)) { +- free(a); +- return NULL; +- } ++ if (snd_config_make_compound(&dst, id, count == 1)) ++ goto lerr; + for (index = 0; index < count; index++) { + snd_config_t *s = a[index]; + const char *id2; + if (snd_config_get_id(s, &id2)) { + snd_config_delete(dst); +- free(a); +- return NULL; ++ goto lerr; + } + s = sort_config(id2, s); + if (s == NULL || snd_config_add(dst, s)) { + if (s) + snd_config_delete(s); + snd_config_delete(dst); +- free(a); +- return NULL; ++ goto lerr; + } + } + free(a); + return dst; ++lerr: ++ free(a); ++ return NULL; + } + + static int tplg_check_quoted(const unsigned char *p) +diff --git a/src/ucm/main.c b/src/ucm/main.c +index 3871d5aa..754b967e 100644 +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -666,7 +666,7 @@ static int get_list0(struct list_head *list, + } + return cnt; + __fail: +- snd_use_case_free_list((const char **)res, cnt); ++ snd_use_case_free_list(*result, cnt); + return -ENOMEM; + } + +@@ -724,7 +724,7 @@ static int get_list20(struct list_head *list, + } + return cnt; + __fail: +- snd_use_case_free_list((const char **)res, cnt); ++ snd_use_case_free_list(*result, cnt); + return -ENOMEM; + } + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index 75b78826..c8bee1f2 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -1575,7 +1575,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, + /* in-place evaluation */ + err = uc_mgr_evaluate_inplace(uc_mgr, cfg); + if (err < 0) +- return err; ++ goto _err; + + /* parse master config sections */ + snd_config_for_each(i, next, cfg) { +diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c +index f608bb09..df6d736f 100644 +--- a/src/ucm/ucm_subs.c ++++ b/src/ucm/ucm_subs.c +@@ -417,11 +417,12 @@ int uc_mgr_substitute_tree(snd_use_case_mgr_t *uc_mgr, snd_config_t *node) + if (err < 0) + return err; + err = snd_config_set_id(node, s); +- free(s); + if (err < 0) { + uc_error("unable to set substituted id '%s' (old id '%s')", s, id); ++ free(s); + return err; + } ++ free(s); + } + if (snd_config_get_type(node) != SND_CONFIG_TYPE_COMPOUND) { + if (snd_config_get_type(node) == SND_CONFIG_TYPE_STRING) { +diff --git a/test/audio_time.c b/test/audio_time.c +index 530922d9..e4d4a944 100644 +--- a/test/audio_time.c ++++ b/test/audio_time.c +@@ -32,7 +32,7 @@ static void usage(char *command) + "-d, --delay add delay \n" + "-D, --device=NAME select PCM by name \n" + "-p, --playback playback tstamps \n" +- "-t, --ts_type=TYPE Default(0),link(1),link_estimated(2),synchronized(3) \n" ++ "-t, --ts_type=TYPE Compat(0),default(1),link(2),link_absolute(3),link_estimated(4),link_synchronized(5) \n" + "-r, --report show audio timestamp and accuracy validity\n" + , command); + } +@@ -201,17 +201,17 @@ int main(int argc, char *argv[]) + goto _exit; + } + +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT)) + printf("Playback supports audio compat timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) + printf("Playback supports audio default timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK)) + printf("Playback supports audio link timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE)) + printf("Playback supports audio link absolute timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED)) + printf("Playback supports audio link estimated timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)) + printf("Playback supports audio link synchronized timestamps\n"); + + snd_pcm_sw_params_alloca(&swparams_p); +@@ -269,17 +269,17 @@ int main(int argc, char *argv[]) + goto _exit; + } + +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT)) + printf("Capture supports audio compat timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) + printf("Capture supports audio default timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK)) + printf("Capture supports audio link timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE)) + printf("Capture supports audio link absolute timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED)) + printf("Capture supports audio link estimated timestamps\n"); +- if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5)) ++ if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)) + printf("Capture supports audio link synchronized timestamps\n"); + + snd_pcm_sw_params_alloca(&swparams_c); diff --git a/SOURCES/alsa-ucm-git.patch b/SOURCES/alsa-ucm-git.patch new file mode 100644 index 0000000..43b9d26 --- /dev/null +++ b/SOURCES/alsa-ucm-git.patch @@ -0,0 +1,433 @@ +diff --git a/ucm2/HDA-Intel/HDAudio-DualCodecs.conf b/ucm2/HDA-Intel/HDAudio-DualCodecs.conf +index 8aaabd0..6fd7bd1 100644 +--- a/ucm2/HDA-Intel/HDAudio-DualCodecs.conf ++++ b/ucm2/HDA-Intel/HDAudio-DualCodecs.conf +@@ -4,3 +4,15 @@ SectionUseCase."HiFi" { + File "HiFi-dual.conf" + Comment "Default" + } ++ ++BootSequence [ ++ cset "name='Headphone Playback Volume' 60%" ++ cset "name='Headphone Playback Switch' off" ++ cset "name='Speaker Playback Volume' 60%" ++ cset "name='Speaker Playback Switch' on" ++ cset "name='Front Playback Volume' 100%" ++ cset "name='Front Playback Switch' on" ++ cset "name='Rear-Panel Capture Volume' 100%" ++ cset "name='Rear-Panel Capture Switch' on" ++ cset "name='Input Source' Rear Mic" ++] +diff --git a/ucm2/HDA-Intel/Hdmi.conf b/ucm2/HDA-Intel/Hdmi.conf +index c8b6e77..c533e49 100644 +--- a/ucm2/HDA-Intel/Hdmi.conf ++++ b/ucm2/HDA-Intel/Hdmi.conf +@@ -6,6 +6,7 @@ If.hdmi1 { + Define { + HdmiNum 1 + HdmiPCM 3 ++ HdmiCtlIndex 0 + HdmiPrio 1100 + } + Include.hdmi1.File "/codecs/hda/hdmi.conf" +@@ -18,6 +19,7 @@ If.hdmi2 { + Define { + HdmiNum 2 + HdmiPCM 7 ++ HdmiCtlIndex 1 + HdmiPrio 1200 + } + Include.hdmi2.File "/codecs/hda/hdmi.conf" +@@ -30,6 +32,7 @@ If.hdmi3 { + Define { + HdmiNum 3 + HdmiPCM 8 ++ HdmiCtlIndex 2 + HdmiPrio 1300 + } + Include.hdmi3.File "/codecs/hda/hdmi.conf" +@@ -42,6 +45,7 @@ If.hdmi4 { + Define { + HdmiNum 4 + HdmiPCM 9 ++ HdmiCtlIndex 3 + HdmiPrio 1400 + } + Include.hdmi4.File "/codecs/hda/hdmi.conf" +@@ -54,6 +58,7 @@ If.hdmi5 { + Define { + HdmiNum 5 + HdmiPCM 10 ++ HdmiCtlIndex 4 + HdmiPrio 1500 + } + Include.hdmi5.File "/codecs/hda/hdmi.conf" +@@ -66,8 +71,9 @@ If.hdmi6 { + Define { + HdmiNum 6 + HdmiPCM 11 ++ HdmiCtlIndex 5 + HdmiPrio 1600 + } +- Include.hdmi5.File "/codecs/hda/hdmi.conf" ++ Include.hdmi6.File "/codecs/hda/hdmi.conf" + } + } +diff --git a/ucm2/HDA-Intel/HiFi-acp.conf b/ucm2/HDA-Intel/HiFi-acp.conf +index 15eeca5..123ae15 100644 +--- a/ucm2/HDA-Intel/HiFi-acp.conf ++++ b/ucm2/HDA-Intel/HiFi-acp.conf +@@ -4,6 +4,5 @@ SectionDevice."Mic1" { + Value { + CapturePriority 100 + CapturePCM "hw:${var:AcpCardId}" +- CaptureMixerElem "Capture" + } + } +diff --git a/ucm2/HDA-Intel/HiFi-dual.conf b/ucm2/HDA-Intel/HiFi-dual.conf +index cff948e..f2c6915 100644 +--- a/ucm2/HDA-Intel/HiFi-dual.conf ++++ b/ucm2/HDA-Intel/HiFi-dual.conf +@@ -8,6 +8,8 @@ SectionVerb { + cset "name='Front Playback Switch' on" + cset "name='Rear-Panel Capture Volume' 100%" + cset "name='Rear-Panel Capture Switch' on" ++ cset "name='Headphone Playback Switch' off" ++ cset "name='Speaker Playback Switch' off" + ] + + DisableSequence [ +@@ -27,6 +29,14 @@ SectionDevice."Speaker" { + PlaybackMixerElem "Speaker" + } + ++ EnableSequence [ ++ cset "name='Speaker Playback Switch' on" ++ ] ++ ++ DisableSequence [ ++ cset "name='Speaker Playback Switch' off" ++ ] ++ + ConflictingDevice [ + "Headphones" + ] +@@ -54,6 +64,14 @@ SectionDevice."Headphones" { + JackHWMute "Speaker" + } + ++ EnableSequence [ ++ cset "name='Headphone Playback Switch' on" ++ ] ++ ++ DisableSequence [ ++ cset "name='Headphone Playback Switch' off" ++ ] ++ + ConflictingDevice [ + "Speaker" + ] +diff --git a/ucm2/HDA-Intel/init.conf b/ucm2/HDA-Intel/init.conf +index 1a351a9..6310eb3 100644 +--- a/ucm2/HDA-Intel/init.conf ++++ b/ucm2/HDA-Intel/init.conf +@@ -15,6 +15,7 @@ If.master { + } + True.BootSequence [ + cset "name='Master Playback Volume' 60%" ++ cset "name='Master Playback Switch' on" + ] + } + +diff --git a/ucm2/chtnau8824/HiFi.conf b/ucm2/chtnau8824/HiFi.conf +index 3ccd6b1..105f360 100644 +--- a/ucm2/chtnau8824/HiFi.conf ++++ b/ucm2/chtnau8824/HiFi.conf +@@ -1,4 +1,5 @@ + Define.Speaker "Speaker" ++Define.Mic "InternalMic" + + If.cfg-mspk { + Condition { +@@ -11,6 +12,19 @@ If.cfg-mspk { + } + } + ++If.cfg-mic { ++ Condition { ++ Type RegexMatch ++ String "${CardLongName}" ++ # Medion E22??T models put DMIC in their product version ++ # when using DMICs ++ Regex "(MEDION-E22..T.*-DMIC-)" ++ } ++ True { ++ Define.Mic "DMIC1_2" ++ } ++} ++ + SectionVerb { + + Value { +@@ -34,8 +48,15 @@ SectionVerb { + } + } + +-Include.spk.File "/codecs/nau8824/${var:Speaker}.conf" +-Include.hp.File "/codecs/nau8824/HeadPhones.conf" ++# The includes using $vars in there path must be conditional otherwise the ++# $var gets expanded before the other If-s above can change the vars. ++If.cfg-includes { ++ Condition { Type String Empty "" } ++ True { ++ Include.spk.File "/codecs/nau8824/${var:Speaker}.conf" ++ Include.hp.File "/codecs/nau8824/HeadPhones.conf" + +-Include.mic.File "/codecs/nau8824/InternalMic.conf" +-Include.hsmic.File "/codecs/nau8824/HeadsetMic.conf" ++ Include.mic.File "/codecs/nau8824/${var:Mic}.conf" ++ Include.hsmic.File "/codecs/nau8824/HeadsetMic.conf" ++ } ++} +diff --git a/ucm2/chtrt5645/HiFi.conf b/ucm2/chtrt5645/HiFi.conf +index 10b0a1c..30fad50 100644 +--- a/ucm2/chtrt5645/HiFi.conf ++++ b/ucm2/chtrt5645/HiFi.conf +@@ -18,7 +18,7 @@ If.cfg-dmic2 { + Condition { + Type RegexMatch + String "${CardLongName}" +- Regex "(LENOVO.*LenovoMIIX320|MEDION.*Wingman)" ++ Regex "(LENOVO.*LenovoMIIX320|MEDION.*Wingman|Standard-EF20EA-1.0)" + } + True { + Define.AnalogMic "" +diff --git a/ucm2/codecs/hda/hdmi.conf b/ucm2/codecs/hda/hdmi.conf +index ba80fef..c7b7ba4 100644 +--- a/ucm2/codecs/hda/hdmi.conf ++++ b/ucm2/codecs/hda/hdmi.conf +@@ -5,14 +5,14 @@ If.hdmi { + } + True { + SectionDevice."HDMI${var:HdmiNum}" { +- Comment "HDMI${var:HdmiNum} Output" ++ Comment "HDMI / DisplayPort ${var:HdmiNum} Output" + + EnableSequence [ +- cset "name='IEC958 Playback Switch' on" ++ cset "name='IEC958 Playback Switch',index=${var:HdmiCtlIndex} on" + ] + + DisableSequence [ +- cset "name='IEC958 Playback Switch' off" ++ cset "name='IEC958 Playback Switch',index=${var:HdmiCtlIndex} off" + ] + + Value { +diff --git a/ucm2/codecs/nau8824/DMIC1_2.conf b/ucm2/codecs/nau8824/DMIC1_2.conf +new file mode 100644 +index 0000000..f54f671 +--- /dev/null ++++ b/ucm2/codecs/nau8824/DMIC1_2.conf +@@ -0,0 +1,30 @@ ++# Stereo DMICs on the DMIC1 and DMIC2 inputs ++ ++SectionDevice."Mic" { ++ Comment "Internal Digital Microphones" ++ ++ Value { ++ CapturePriority 200 ++ CapturePCM "hw:${CardId}" ++ } ++ ++ ConflictingDevice [ ++ "Headset" ++ ] ++ ++ EnableSequence [ ++ # Note needs to be swapped / swap is deliberate! ++ cset "name='ADC CH0 Select' 1" ++ cset "name='ADC CH1 Select' 0" ++ ++ cset "name='Int Mic Switch' on" ++ cset "name='DMIC1 Enable Switch' on" ++ cset "name='DMIC2 Enable Switch' on" ++ ] ++ ++ DisableSequence [ ++ cset "name='Int Mic Switch' off" ++ cset "name='DMIC1 Enable Switch' off" ++ cset "name='DMIC2 Enable Switch' off" ++ ] ++} +diff --git a/ucm2/codecs/nau8824/EnableSeq.conf b/ucm2/codecs/nau8824/EnableSeq.conf +index 433e8e2..3650d06 100644 +--- a/ucm2/codecs/nau8824/EnableSeq.conf ++++ b/ucm2/codecs/nau8824/EnableSeq.conf +@@ -7,8 +7,8 @@ EnableSequence [ + cset "name='DMIC2 Enable Switch' off" + cset "name='DMIC3 Enable Switch' off" + cset "name='DMIC4 Enable Switch' off" +- cset "name='MIC1 Volume' 10" +- cset "name='MIC2 Volume' 10" ++ cset "name='MIC1 Volume' 14" ++ cset "name='MIC2 Volume' 14" + # Button Configuration + cset "name='THD for key media' 10" + cset "name='THD for key voice command' 16" +diff --git a/ucm2/codecs/rt715/init.conf b/ucm2/codecs/rt715/init.conf +index 6e07b2d..15a0571 100644 +--- a/ucm2/codecs/rt715/init.conf ++++ b/ucm2/codecs/rt715/init.conf +@@ -7,4 +7,5 @@ BootSequence [ + cset "name='rt715 ADC 25 Mux' 4" + cset "name='rt715 ADC 27 Capture Switch' 1" + cset "name='rt715 ADC 07 Capture Switch' 1" ++ cset "name='rt715 ADC 07 Capture Volume' 58" + ] +diff --git a/ucm2/sof-hda-dsp/Hdmi.conf b/ucm2/sof-hda-dsp/Hdmi.conf +index 7b777d1..1726567 100644 +--- a/ucm2/sof-hda-dsp/Hdmi.conf ++++ b/ucm2/sof-hda-dsp/Hdmi.conf +@@ -6,6 +6,7 @@ If.hdmi1 { + Define { + HdmiNum 1 + HdmiPCM 3 ++ HdmiCtlIndex 0 + HdmiPrio 500 + } + Include.hdmi1.File "/codecs/hda/hdmi.conf" +@@ -18,6 +19,7 @@ If.hdmi2 { + Define { + HdmiNum 2 + HdmiPCM 4 ++ HdmiCtlIndex 1 + HdmiPrio 600 + } + Include.hdmi2.File "/codecs/hda/hdmi.conf" +@@ -30,6 +32,7 @@ If.hdmi3 { + Define { + HdmiNum 3 + HdmiPCM 5 ++ HdmiCtlIndex 2 + HdmiPrio 700 + } + Include.hdmi3.File "/codecs/hda/hdmi.conf" +diff --git a/ucm2/sof-hda-dsp/sof-hda-dsp.conf b/ucm2/sof-hda-dsp/sof-hda-dsp.conf +index c8069a6..79b54a9 100644 +--- a/ucm2/sof-hda-dsp/sof-hda-dsp.conf ++++ b/ucm2/sof-hda-dsp/sof-hda-dsp.conf +@@ -24,6 +24,7 @@ If.master { + } + True.BootSequence [ + cset "name='Master Playback Volume' 60%" ++ cset "name='Master Playback Switch' on" + ] + } + +diff --git a/ucm2/sof-soundwire/Hdmi.conf b/ucm2/sof-soundwire/Hdmi.conf +index d0ba790..d5ee9c6 100644 +--- a/ucm2/sof-soundwire/Hdmi.conf ++++ b/ucm2/sof-soundwire/Hdmi.conf +@@ -1,79 +1,40 @@ +-# Use case Configuration for sof-soundwire card ++# Use case Configuration for sof-soundwire + + If.hdmi1 { +- Condition { +- Type ControlExists +- Control "iface=CARD,name='HDMI/DP,pcm=5 Jack'" +- } ++ Condition { Type String Empty "" } + True { +- SectionDevice."HDMI1" { +- Comment "HDMI1/DP1 Output" +- +- EnableSequence [ +- cset "name='IEC958 Playback Switch' on" +- ] +- +- DisableSequence [ +- cset "name='IEC958 Playback Switch' off" +- ] +- +- Value { +- PlaybackPriority 500 +- PlaybackPCM "hw:${CardId},5" +- JackControl "HDMI/DP,pcm=5 Jack" +- } ++ Define { ++ HdmiNum 1 ++ HdmiPCM 5 ++ HdmiCtlIndex 0 ++ HdmiPrio 500 + } ++ Include.hdmi1.File "/codecs/hda/hdmi.conf" + } + } + + If.hdmi2 { +- Condition { +- Type ControlExists +- Control "iface=CARD,name='HDMI/DP,pcm=6 Jack'" +- } ++ Condition { Type String Empty "" } + True { +- SectionDevice."HDMI2" { +- Comment "HDMI2/DP2 Output" +- +- EnableSequence [ +- cset "name='IEC958 Playback Switch',index=1 on" +- ] +- +- DisableSequence [ +- cset "name='IEC958 Playback Switch',index=1 off" +- ] +- +- Value { +- PlaybackPriority 600 +- PlaybackPCM "hw:${CardId},6" +- JackControl "HDMI/DP,pcm=6 Jack" +- } ++ Define { ++ HdmiNum 2 ++ HdmiPCM 6 ++ HdmiCtlIndex 1 ++ HdmiPrio 600 + } ++ Include.hdmi2.File "/codecs/hda/hdmi.conf" + } + } + + If.hdmi3 { +- Condition { +- Type ControlExists +- Control "iface=CARD,name='HDMI/DP,pcm=7 Jack'" +- } ++ Condition { Type String Empty "" } + True { +- SectionDevice."HDMI3" { +- Comment "HDMI3/DP3 Output" +- +- EnableSequence [ +- cset "name='IEC958 Playback Switch',index=2 on" +- ] +- +- DisableSequence [ +- cset "name='IEC958 Playback Switch',index=2 off" +- ] +- +- Value { +- PlaybackPriority 700 +- PlaybackPCM "hw:${CardId},7" +- JackControl "HDMI/DP,pcm=7 Jack" +- } ++ Define { ++ HdmiNum 3 ++ HdmiPCM 7 ++ HdmiCtlIndex 2 ++ HdmiPrio 700 + } ++ Include.hdmi3.File "/codecs/hda/hdmi.conf" + } + } diff --git a/SPECS/alsa-lib.spec b/SPECS/alsa-lib.spec index ee43870..5d5c9f3 100644 --- a/SPECS/alsa-lib.spec +++ b/SPECS/alsa-lib.spec @@ -9,7 +9,7 @@ Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib Version: %{version_alsa_lib} -Release: 3%{?prever_dot}%{?dist} +Release: 4%{?prever_dot}%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.alsa-project.org/ @@ -20,7 +20,8 @@ Source2: ftp://ftp.alsa-project.org/pub/lib/alsa-topology-conf-%{version_alsa_t Source10: asound.conf Source11: modprobe-dist-alsa.conf Source12: modprobe-dist-oss.conf -#Patch0: alsa-git.patch +Source20: alsa-ucm-git.patch +Patch0: alsa-git.patch Patch1: alsa-lib-1.2.3-config.patch Patch2: alsa-lib-1.0.14-glibc-open.patch @@ -73,7 +74,7 @@ contains alsa-lib configuration of SoC topology %prep %setup -q -n %{name}-%{version}%{?prever}%{?postver} -#patch0 -p1 -b .alsa-git +%patch0 -p1 -b .alsa-git %patch1 -p1 -b .config %patch2 -p1 -b .glibc-open @@ -109,6 +110,7 @@ mkdir -p %{buildroot}/%{_datadir}/alsa/ucm2 # Unpack UCMs tar xvjf %{SOURCE1} -C %{buildroot}/%{_datadir}/alsa --strip-components=1 "*/ucm" "*/ucm2" +patch -d %{buildroot}/%{_datadir}/alsa -p1 < %{SOURCE20} # Create topology directory mkdir -p %{buildroot}/%{_datadir}/alsa/topology @@ -161,6 +163,9 @@ rm %{buildroot}/%{_includedir}/asoundlib.h %{_datadir}/alsa/topology %changelog +* Fri Jan 8 2021 Jaroslav Kysela - 1.2.4-4 +- Apply fixes from upstream (alsa-lib, alsa-ucm-conf) + * Mon Oct 19 2020 Jaroslav Kysela - 1.2.4-3 - Updated to 1.2.4