From ea9e1d7987c5d20a47904d15db24d455193dbf81 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 10 2018 05:40:43 +0000 Subject: import alsa-lib-1.1.4.1-2.el7 --- diff --git a/.alsa-lib.metadata b/.alsa-lib.metadata index 0e23661..3dd896f 100644 --- a/.alsa-lib.metadata +++ b/.alsa-lib.metadata @@ -1 +1 @@ -8ef0b9725296ac8f24e06f20196f5b2b62ab27a9 SOURCES/alsa-lib-1.1.3.tar.bz2 +628634afbdc19054fca26d714aa6c2f1e41e465d SOURCES/alsa-lib-1.1.4.1.tar.bz2 diff --git a/.gitignore b/.gitignore index 93e2d4a..f2718d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/alsa-lib-1.1.3.tar.bz2 +SOURCES/alsa-lib-1.1.4.1.tar.bz2 diff --git a/SOURCES/alsa-lib-1.1.3-post.patch b/SOURCES/alsa-lib-1.1.3-post.patch deleted file mode 100644 index d0f5fc8..0000000 --- a/SOURCES/alsa-lib-1.1.3-post.patch +++ /dev/null @@ -1,3874 +0,0 @@ -From 6ad2a9763d9aaab30c0470d039877b1bb61dda3b Mon Sep 17 00:00:00 2001 -From: Mengdong Lin -Date: Tue, 27 Dec 2016 18:08:58 +0800 -Subject: [PATCH 01/37] ucm: Add ATTRIBUTE_UNUSED for unused parameters of - execute_component_seq() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To fix the following warnings: - -main.c: In function ‘execute_component_seq’: -main.c:489:24: warning: unused parameter ‘value_list1’ [-Wunused-parameter] - struct list_head *value_list1, - ^ -main.c:490:24: warning: unused parameter ‘value_list2’ [-Wunused-parameter] - struct list_head *value_list2, - ^ -main.c:491:24: warning: unused parameter ‘value_list3’ [-Wunused-parameter] - struct list_head *value_list3, - ^ - -Signed-off-by: Mengdong Lin -Signed-off-by: Takashi Iwai ---- - src/ucm/main.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/ucm/main.c b/src/ucm/main.c -index 750e65d..38a5e81 100644 ---- a/src/ucm/main.c -+++ b/src/ucm/main.c -@@ -486,9 +486,9 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, - */ - static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, - struct component_sequence *cmpt_seq, -- struct list_head *value_list1, -- struct list_head *value_list2, -- struct list_head *value_list3, -+ struct list_head *value_list1 ATTRIBUTE_UNUSED, -+ struct list_head *value_list2 ATTRIBUTE_UNUSED, -+ struct list_head *value_list3 ATTRIBUTE_UNUSED, - char *cdev) - { - struct use_case_device *device = cmpt_seq->device; --- -2.9.3 - - -From 9ed4075f05a4242f32331f7f2c365767970f5003 Mon Sep 17 00:00:00 2001 -From: Gustavo Zacarias -Date: Wed, 21 Dec 2016 19:46:34 -0300 -Subject: [PATCH 02/37] ucm: parser needs limits.h - -It's using PATH_MAX which is defined there, otherwise the build fails on -musl libc. - -Signed-off-by: Gustavo Zacarias -Signed-off-by: Takashi Iwai ---- - src/ucm/parser.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/ucm/parser.c b/src/ucm/parser.c -index c98373a..f520abc 100644 ---- a/src/ucm/parser.c -+++ b/src/ucm/parser.c -@@ -32,6 +32,7 @@ - - #include "ucm_local.h" - #include -+#include - - /** The name of the environment variable containing the UCM directory */ - #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" --- -2.9.3 - - -From 0a61c796810fcec8b386e5311e871b1744b45a67 Mon Sep 17 00:00:00 2001 -From: Joshua Frkuska -Date: Fri, 30 Dec 2016 11:56:15 +0530 -Subject: [PATCH 03/37] pcm: direct: allow users to configure different period - sizes - -This patch allows the effective period size to be a multiple of the -slave-pcm period size. -Allowing only exact multiple of original period size is achieved by -borrowing code from the kernel hwrules implementation. - -This patch is intended to save cpu workload when for example, the -slave operates with very small periods but a user does not need that -small periods. - -This feature is enabled by default and can be disabled by adding -config option 'var_periodsize 0'. - -Signed-off-by: Alexander Jahn -Signed-off-by: Andreas Pape -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++------ - src/pcm/pcm_direct.h | 3 ++ - src/pcm/pcm_dmix.c | 1 + - src/pcm/pcm_dshare.c | 1 + - src/pcm/pcm_dsnoop.c | 1 + - 5 files changed, 84 insertions(+), 10 deletions(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index 6434983..f5d922f 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -660,6 +660,29 @@ static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params, - return hw_param_interval_refine_one(params, var, &t); - } - -+/* this code is used 'as-is' from the alsa kernel code */ -+static int snd_interval_step(struct snd_interval *i, unsigned int min, -+ unsigned int step) -+{ -+ unsigned int n; -+ int changed = 0; -+ n = (i->min - min) % step; -+ if (n != 0 || i->openmin) { -+ i->min += step - n; -+ changed = 1; -+ } -+ n = (i->max - min) % step; -+ if (n != 0 || i->openmax) { -+ i->max -= n; -+ changed = 1; -+ } -+ if (snd_interval_checkempty(i)) { -+ i->empty = 1; -+ return -EINVAL; -+ } -+ return changed; -+} -+ - #undef REFINE_DEBUG - - int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) -@@ -710,15 +733,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) - &dshare->shmptr->hw.rate); - if (err < 0) - return err; -- err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, -- &dshare->shmptr->hw.period_size); -- if (err < 0) -- return err; -- err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, -- &dshare->shmptr->hw.period_time); -- if (err < 0) -- return err; -+ - if (dshare->max_periods < 0) { -+ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, -+ &dshare->shmptr->hw.period_size); -+ if (err < 0) -+ return err; -+ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, -+ &dshare->shmptr->hw.period_time); -+ if (err < 0) -+ return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, - &dshare->shmptr->hw.buffer_size); - if (err < 0) -@@ -730,11 +754,38 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) - } else if (params->rmask & ((1<shmptr->hw.period_size; -+ snd_interval_t period_time = dshare->shmptr->hw.period_time; - int changed; - unsigned int max_periods = dshare->max_periods; - if (max_periods < 2) - max_periods = dshare->slave_buffer_size / dshare->slave_period_size; -+ -+ /* make sure buffer size does not exceed slave buffer size */ -+ err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE, -+ 2 * dshare->slave_period_size, dshare->slave_buffer_size); -+ if (err < 0) -+ return err; -+ if (dshare->var_periodsize) { -+ /* more tolerant settings... */ -+ if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max) -+ period_size.max = dshare->shmptr->hw.buffer_size.max / 2; -+ if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max) -+ period_time.max = dshare->shmptr->hw.buffer_time.max / 2; -+ } -+ -+ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, -+ &period_size); -+ if (err < 0) -+ return err; -+ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, -+ &period_time); -+ if (err < 0) -+ return err; - do { - changed = 0; - err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS, -@@ -746,8 +797,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) - if (err < 0) - return err; - changed |= err; -+ err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), -+ 0, dshare->slave_period_size); -+ if (err < 0) -+ return err; -+ changed |= err; -+ if (err) -+ params->rmask |= (1 << SND_PCM_HW_PARAM_PERIOD_SIZE); - } while (changed); - } -+ dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max / dshare->slave_period_size; - params->info = dshare->shmptr->s.info; - #ifdef REFINE_DEBUG - snd_output_puts(log, "DMIX REFINE (end):\n"); -@@ -1183,6 +1242,7 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) - - dmix->tread = 1; - dmix->timer_need_poll = 0; -+ dmix->timer_ticks = 1; - ret = snd_pcm_info(dmix->spcm, &info); - if (ret < 0) { - SNDERR("unable to info for slave pcm"); -@@ -1366,7 +1426,7 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) - snd_timer_params_set_auto_start(¶ms, 1); - if (dmix->type != SND_PCM_TYPE_DSNOOP) - snd_timer_params_set_early_event(¶ms, 1); -- snd_timer_params_set_ticks(¶ms, 1); -+ snd_timer_params_set_ticks(¶ms, dmix->timer_ticks); - if (dmix->tread) { - filter = (1<timer_events; -@@ -1656,6 +1716,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, - rec->ipc_gid = -1; - rec->slowptr = 1; - rec->max_periods = 0; -+ rec->var_periodsize = 1; - - /* read defaults */ - if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { -@@ -1762,6 +1823,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, - rec->max_periods = val; - continue; - } -+ if (strcmp(id, "var_periodsize") == 0) { -+ err = snd_config_get_bool(n); -+ if (err < 0) -+ return err; -+ rec->var_periodsize = err; -+ continue; -+ } - SNDERR("Unknown field %s", id); - return -EINVAL; - } -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index 611ad29..91e816c 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -147,12 +147,14 @@ struct snd_pcm_direct { - int tread: 1; - int timer_need_poll: 1; - unsigned int timer_events; -+ unsigned int timer_ticks; - int server_fd; - pid_t server_pid; - snd_timer_t *timer; /* timer used as poll_fd */ - int interleaved; /* we have interleaved buffer */ - int slowptr; /* use slow but more precise ptr updates */ - int max_periods; /* max periods (-1 = fixed periods, 0 = max buffer size) */ -+ int var_periodsize; /* allow variable period size if max_periods is != -1*/ - unsigned int channels; /* client's channels */ - unsigned int *bindings; - union { -@@ -326,6 +328,7 @@ struct snd_pcm_direct_open_conf { - int ipc_gid; - int slowptr; - int max_periods; -+ int var_periodsize; - snd_config_t *slave; - snd_config_t *bindings; - }; -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 825677f..0ab7323 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -1040,6 +1040,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, - dmix->state = SND_PCM_STATE_OPEN; - dmix->slowptr = opts->slowptr; - dmix->max_periods = opts->max_periods; -+ dmix->var_periodsize = opts->var_periodsize; - dmix->sync_ptr = snd_pcm_dmix_sync_ptr; - - retry: -diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c -index 29cd6c6..a1fed5d 100644 ---- a/src/pcm/pcm_dshare.c -+++ b/src/pcm/pcm_dshare.c -@@ -725,6 +725,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, - dshare->state = SND_PCM_STATE_OPEN; - dshare->slowptr = opts->slowptr; - dshare->max_periods = opts->max_periods; -+ dshare->var_periodsize = opts->var_periodsize; - dshare->sync_ptr = snd_pcm_dshare_sync_ptr; - - retry: -diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c -index 1aedf3c..85f0ff4 100644 ---- a/src/pcm/pcm_dsnoop.c -+++ b/src/pcm/pcm_dsnoop.c -@@ -606,6 +606,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, - dsnoop->state = SND_PCM_STATE_OPEN; - dsnoop->slowptr = opts->slowptr; - dsnoop->max_periods = opts->max_periods; -+ dsnoop->var_periodsize = opts->var_periodsize; - dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; - - retry: --- -2.9.3 - - -From 8eeee1ab7d7db3110b7b3bb31cfb989304dced94 Mon Sep 17 00:00:00 2001 -From: Alexander Jahn -Date: Fri, 30 Dec 2016 11:59:11 +0530 -Subject: [PATCH 04/37] pcm: dshare: enable silence - -This issue depends on system load - if the process using dshare is -scheduled fast enough, then there is no noise. A delay of e.g >~2ms -produces hearable noise. - -Reproduction with instrumented aplay(sleep every 100th period for a -given time): -During the sleep time of 2000000us (2s) the hardware plays old samples -in a loop before xrun is detected and recovered after the sleep. -This is resolved by placing it in silence, in case of dshare plugin. - -Signed-off-by: Alexander Jahn -Signed-off-by: Andreas Pape -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index f5d922f..0770abc 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -1161,7 +1161,8 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str - return ret; - } - -- if (dmix->type != SND_PCM_TYPE_DMIX) -+ if (dmix->type != SND_PCM_TYPE_DMIX && -+ dmix->type != SND_PCM_TYPE_DSHARE) - goto __skip_silencing; - - ret = snd_pcm_sw_params_set_silence_threshold(spcm, &sw_params, 0); --- -2.9.3 - - -From 7570e5d77514d8d8af387da04a010fa2ccaf543c Mon Sep 17 00:00:00 2001 -From: "mahendran.k" -Date: Fri, 30 Dec 2016 11:59:27 +0530 -Subject: [PATCH 05/37] pcm: rate: fix the hw_ptr update until the boundary - available - -For long time test case, the slave_hw_ptr will exceed the boundary -and wraparound the slave_hw_ptr. This slave boundary wraparound will -cause the rate->hw_ptr to wraparound irrespective of the -rate->boundary availability and due to that the available size goes -wrong. - -Hence, to get the correct available size, -- Its necessary to increment the rate->hw_ptr upto the rate->boundary -and then wraparound the rate->hw_ptr. -- While handling fraction part of slave period, rounded value will be -introduced by input_frames(). To eliminate rounding issue on -rate->hw_ptr, subtract last rounded value from rate->hw_ptr and add -new rounded value of present slave_hw_ptr fraction part to -rate->hw_ptr. - -Signed-off-by: mahendran.k -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_rate.c | 31 +++++++++++++++++++++++++------ - 1 file changed, 25 insertions(+), 6 deletions(-) - -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 1f830dd..61cf979 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -50,7 +50,7 @@ typedef struct _snd_pcm_rate snd_pcm_rate_t; - - struct _snd_pcm_rate { - snd_pcm_generic_t gen; -- snd_pcm_uframes_t appl_ptr, hw_ptr; -+ snd_pcm_uframes_t appl_ptr, hw_ptr, last_slave_hw_ptr; - snd_pcm_uframes_t last_commit_ptr; - snd_pcm_uframes_t orig_avail_min; - snd_pcm_sw_params_t sw_params; -@@ -563,14 +563,31 @@ static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t sl - { - 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_sframes_t last_slave_hw_ptr_frac; -+ - if (pcm->stream != SND_PCM_STREAM_PLAYBACK) - return; -- /* FIXME: boundary overlap of slave hw_ptr isn't evaluated here! -- * e.g. if slave rate is small... -+ -+ if (slave_hw_ptr_diff < 0) -+ slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */ -+ else 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 -+ * introduced by input_frames(). -+ * To eliminate rounding issue on rate->hw_ptr, subtract last rounded -+ * value from rate->hw_ptr and add new rounded value of present -+ * slave_hw_ptr fraction part to rate->hw_ptr. Hence, -+ * rate->hw_ptr += [ (no. of updated slave periods * pcm rate period size) - -+ * fractional part of last_slave_hw_ptr rounded value + -+ * fractional part of updated slave hw ptr's rounded value ] - */ -- rate->hw_ptr = -- (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size + -- rate->ops.input_frames(rate->obj, slave_hw_ptr % rate->gen.slave->period_size); -+ rate->hw_ptr += ( -+ (((last_slave_hw_ptr_frac + slave_hw_ptr_diff) / rate->gen.slave->period_size) * pcm->period_size) - -+ rate->ops.input_frames(rate->obj, last_slave_hw_ptr_frac) + -+ rate->ops.input_frames(rate->obj, (last_slave_hw_ptr_frac + slave_hw_ptr_diff) % rate->gen.slave->period_size)); -+ rate->last_slave_hw_ptr = slave_hw_ptr; - - rate->hw_ptr %= pcm->boundary; - } -@@ -635,6 +652,7 @@ static int snd_pcm_rate_prepare(snd_pcm_t *pcm) - return err; - *pcm->hw.ptr = 0; - *pcm->appl.ptr = 0; -+ rate->last_slave_hw_ptr = 0; - err = snd_pcm_rate_init(pcm); - if (err < 0) - return err; -@@ -650,6 +668,7 @@ static int snd_pcm_rate_reset(snd_pcm_t *pcm) - return err; - *pcm->hw.ptr = 0; - *pcm->appl.ptr = 0; -+ rate->last_slave_hw_ptr = 0; - err = snd_pcm_rate_init(pcm); - if (err < 0) - return err; --- -2.9.3 - - -From 88e4ae27bb4e47029ed57cc8e02fb1ddf2157fd9 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Mon, 19 Dec 2016 12:37:50 +0900 -Subject: [PATCH 06/37] plugin: dynamically update avail_min on slave - -mmapped capture access on some plugins can fetch data from -slave in the 'background'. A subsequent snd_pcm_wait waits -for too long time to reach avail_min threshold again. -Waiting too long leads to xruns on other devices waiting for -the capture data. -As a fix the avail_min on slave is recalculated dynamically. - -V2: updated patch to fix within 80 characters per line - -Signed-off-by: Andreas Pape -Signed-off-by: Jiada Wang -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_plugin.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 63 insertions(+), 1 deletion(-) - -diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c -index e53c5bb..5b65ac3 100644 ---- a/src/pcm/pcm_plugin.c -+++ b/src/pcm/pcm_plugin.c -@@ -535,6 +535,68 @@ static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - return 0; - } - -+static int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, -+ snd_pcm_uframes_t avail) -+{ -+ if (pcm->stream == SND_PCM_STREAM_CAPTURE && -+ pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && -+ pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { -+ /* mmap access on capture device already consumes data from -+ * slave in avail_update operation. Entering snd_pcm_wait after -+ * having already consumed some fragments leads to waiting for -+ * too long time, as slave will unnecessarily wait for avail_min -+ * condition reached again. To avoid unnecessary wait times we -+ * adapt the avail_min threshold on slave dynamically. Just -+ * modifying slave->avail_min as a shortcut and lightweight -+ * solution does not work for all slave plugin types and in -+ * addition it will not propagate the change through all -+ * downstream plugins, so we have to use the sw_params API. -+ * note: reading fragmental parts from slave will only happen -+ * in case -+ * a) the slave can provide contineous hw_ptr between periods -+ * b) avail_min does not match one slave_period -+ */ -+ snd_pcm_plugin_t *plugin = pcm->private_data; -+ snd_pcm_t *slave = plugin->gen.slave; -+ snd_pcm_uframes_t needed_slave_avail_min; -+ snd_pcm_sframes_t available; -+ -+ /* update, as it might have changed. This will also call -+ * avail_update on slave and also can return error -+ */ -+ available = snd_pcm_avail_update(pcm); -+ if (available < 0) -+ return 0; -+ -+ if (available >= pcm->avail_min) -+ /* don't wait at all. As we can't configure avail_min -+ * of slave to 0 return here -+ */ -+ return 0; -+ -+ needed_slave_avail_min = pcm->avail_min - available; -+ if (slave->avail_min != needed_slave_avail_min) { -+ snd_pcm_sw_params_t *swparams; -+ snd_pcm_sw_params_alloca(&swparams); -+ /* pray that changing sw_params while running is -+ * properly implemented in all downstream plugins... -+ * it's legal but not commonly used. -+ */ -+ snd_pcm_sw_params_current(slave, swparams); -+ /* snd_pcm_sw_params_set_avail_min() restricts setting -+ * to >= period size. This conflicts at least with our -+ * dshare patch which allows combining multiple periods -+ * or with slaves which return hw postions between -+ * periods -> set directly in sw_param structure -+ */ -+ swparams->avail_min = needed_slave_avail_min; -+ snd_pcm_sw_params(slave, swparams); -+ } -+ avail = available; -+ } -+ return snd_pcm_generic_may_wait_for_avail_min(pcm, avail); -+} -+ - const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { - .status = snd_pcm_plugin_status, - .state = snd_pcm_generic_state, -@@ -564,7 +626,7 @@ const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { - .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, - .poll_descriptors = snd_pcm_generic_poll_descriptors, - .poll_revents = snd_pcm_generic_poll_revents, -- .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, -+ .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, - }; - - #endif --- -2.9.3 - - -From ff1f669df4b05da3c44dc4a79ce00233fe9de9b7 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Mon, 19 Dec 2016 12:37:51 +0900 -Subject: [PATCH 07/37] rate: dynamic update avail_min on slave - -Signed-off-by: Andreas Pape -Signed-off-by: Jiada Wang -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_plugin.c | 4 ++-- - src/pcm/pcm_plugin.h | 3 +++ - src/pcm/pcm_rate.c | 2 +- - 3 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c -index 5b65ac3..ad4a102 100644 ---- a/src/pcm/pcm_plugin.c -+++ b/src/pcm/pcm_plugin.c -@@ -535,8 +535,8 @@ static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - return 0; - } - --static int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, -- snd_pcm_uframes_t avail) -+int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, -+ snd_pcm_uframes_t avail) - { - if (pcm->stream == SND_PCM_STREAM_CAPTURE && - pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && -diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h -index 217f075..95aacb3 100644 ---- a/src/pcm/pcm_plugin.h -+++ b/src/pcm/pcm_plugin.h -@@ -50,6 +50,8 @@ typedef struct { - /* make local functions really local */ - #define snd_pcm_plugin_init \ - snd1_pcm_plugin_init -+#define snd_pcm_plugin_may_wait_for_avail_min \ -+ snd1_pcm_plugin_may_wait_for_avail_min - #define snd_pcm_plugin_fast_ops \ - snd1_pcm_plugin_fast_ops - #define snd_pcm_plugin_undo_read_generic \ -@@ -64,6 +66,7 @@ typedef struct { - void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin); - snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); - snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); -+int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail); - - extern const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; - -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 61cf979..cbb7618 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -1213,7 +1213,7 @@ static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = { - .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, - .poll_descriptors = snd_pcm_generic_poll_descriptors, - .poll_revents = snd_pcm_rate_poll_revents, -- .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, -+ .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, - }; - - static const snd_pcm_ops_t snd_pcm_rate_ops = { --- -2.9.3 - - -From 6f7eaf92e7de73eb32bd97bad83a14fcb0f408f7 Mon Sep 17 00:00:00 2001 -From: Takashi Sakamoto -Date: Wed, 30 Nov 2016 00:44:32 +0900 -Subject: [PATCH 08/37] topology: fix unused-const-variable warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Last year, unused static const variable was added, then compiler generates -a below warning. - -dapm.c:43:30: warning: ‘widget_control_map’ defined but not used [-Wunused-const-variable=] - static const struct map_elem widget_control_map[] = { - ^~~~~~~~~~~~~~~~~~ - -This commit removes it. - -Fixes: 01a0e1a1c219 ("topology: Add DAPM object parser") -Signed-off-by: Takashi Sakamoto -Acked-by: Liam Girdwood -Signed-off-by: Takashi Iwai ---- - src/topology/dapm.c | 8 -------- - 1 file changed, 8 deletions(-) - -diff --git a/src/topology/dapm.c b/src/topology/dapm.c -index e830751..8c585a7 100644 ---- a/src/topology/dapm.c -+++ b/src/topology/dapm.c -@@ -39,14 +39,6 @@ static const struct map_elem widget_map[] = { - {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK}, - }; - --/* mapping of widget kcontrol text names to types */ --static const struct map_elem widget_control_map[] = { -- {"volsw", SND_SOC_TPLG_DAPM_CTL_VOLSW}, -- {"enum_double", SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE}, -- {"enum_virt", SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT}, -- {"enum_value", SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE}, --}; -- - static int lookup_widget(const char *w) - { - unsigned int i; --- -2.9.3 - - -From 1eddf1f918845d1e6cbcac5516319b20cad80f2f Mon Sep 17 00:00:00 2001 -From: Adam Goode -Date: Tue, 3 Jan 2017 08:33:42 -0500 -Subject: [PATCH 09/37] seq: improve documentation about new get pid/card - functions - -Document the technique for determining if the running kernel supports -the new snd_seq_client_info_get_pid and snd_seq_client_info_get_card -functions. Also add a little information about how to use these -functions and add some cross references. - -Signed-off-by: Adam Goode -Signed-off-by: Takashi Iwai ---- - src/seq/seq.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 42 insertions(+), 2 deletions(-) - -diff --git a/src/seq/seq.c b/src/seq/seq.c -index 9279830..b206e2f 100644 ---- a/src/seq/seq.c -+++ b/src/seq/seq.c -@@ -1530,7 +1530,25 @@ int snd_seq_client_info_get_error_bounce(const snd_seq_client_info_t *info) - * \param info client_info container - * \return card number or -1 if value is not available. - * -- * Only available for SND_SEQ_KERNEL_CLIENT clients. -+ * Only available for #SND_SEQ_KERNEL_CLIENT clients. -+ * -+ * The card number can be used to query state about the hardware -+ * device providing this client, by concatenating "hw:CARD=" -+ * with the card number and using it as the name parameter -+ * to #snd_ctl_open(). -+ * -+ * \note -+ * The return value of -1 is returned for two different conditions: when the -+ * running kernel does not support this operation, and when the client -+ * does not have a hardware card attached. See -+ * #snd_seq_client_info_get_pid() for a way to determine if the -+ * currently running kernel has support for this operation. -+ * -+ * \sa snd_seq_client_info_get_pid(), -+ * snd_card_get_name(), -+ * snd_card_get_longname(), -+ * snd_ctl_open(), -+ * snd_ctl_card_info() - */ - int snd_seq_client_info_get_card(const snd_seq_client_info_t *info) - { -@@ -1543,7 +1561,29 @@ int snd_seq_client_info_get_card(const snd_seq_client_info_t *info) - * \param info client_info container - * \return pid or -1 if value is not available. - * -- * Only available for SND_SEQ_USER_CLIENT clients. -+ * Only available for #SND_SEQ_USER_CLIENT clients. -+ * -+ * \note -+ * The functionality for getting a client's PID and getting a -+ * client's card was added to the kernel at the same time, so you can -+ * use this function to determine if the running kernel -+ * supports reporting these values. If your own client has a valid -+ * PID as reported by this function, then the running kernel supports -+ * both #snd_seq_client_info_get_card() and #snd_seq_client_info_get_pid(). -+ * -+ * \note -+ * Example code for determining kernel support: -+ * \code -+ * int is_get_card_or_pid_supported(snd_seq_t *seq) -+ * { -+ * snd_seq_client_info_t *my_client_info; -+ * snd_seq_client_info_alloca(&my_client_info); -+ * snd_seq_get_client_info(seq, my_client_info); -+ * return snd_seq_client_info_get_pid(my_client_info) != -1; -+ * } -+ * \endcode -+ * -+ * \sa snd_seq_client_info_get_card() - */ - int snd_seq_client_info_get_pid(const snd_seq_client_info_t *info) - { --- -2.9.3 - - -From 3f0dc404f16af58d20b4489b0daafcf87555dfb7 Mon Sep 17 00:00:00 2001 -From: Mounesh Sutar -Date: Tue, 10 Jan 2017 12:03:17 +0530 -Subject: [PATCH 10/37] pcm: direct: returning semop error code for semaphore - up/down failures - -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.h | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index 91e816c..aee38c5 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -263,7 +263,10 @@ static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_ - { - struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } }; - int err = semop(dmix->semid, op, 2); -- if (err == 0) dmix->locked[sem_num]++; -+ if (err == 0) -+ dmix->locked[sem_num]++; -+ else if (err == -1) -+ err = -errno; - return err; - } - -@@ -271,7 +274,10 @@ static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_nu - { - struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT }; - int err = semop(dmix->semid, &op, 1); -- if (err == 0) dmix->locked[sem_num]--; -+ if (err == 0) -+ dmix->locked[sem_num]--; -+ else if (err == -1) -+ err = -errno; - return err; - } - --- -2.9.3 - - -From 1a9bd0f0448106b917ae7f7bedccfcbf6ce84802 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Tue, 10 Jan 2017 12:03:36 +0530 -Subject: [PATCH 11/37] pcm: direct: Fix for sync issue on xrun recover - -If using very short periods, DSHARE/DSNOOP/DMIX may report underruns while in -status 'prepared'. This prohibits correct recovery. Now slave xrun conditions -for DSHARE/DSNOOP/DMIX are being handled properly. - -Signed-off-by: Andreas Pape -Signed-off-by: Joshua Frkuska -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ - src/pcm/pcm_direct.h | 5 ++- - src/pcm/pcm_dmix.c | 27 +++++++++++--- - src/pcm/pcm_dshare.c | 29 +++++++++++---- - src/pcm/pcm_dsnoop.c | 15 +++++++- - 5 files changed, 162 insertions(+), 16 deletions(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index 0770abc..a512dd2 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -550,6 +550,101 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) - return 0; - } - -+/* -+ * Recover slave on XRUN. -+ * Even if direct plugins disable xrun detection, there might be an xrun -+ * raised directly by some drivers. -+ * The first client recovers slave pcm. -+ * Each client needs to execute sw xrun handling afterwards -+ */ -+int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct) -+{ -+ int ret; -+ int semerr; -+ -+ semerr = snd_pcm_direct_semaphore_down(direct, -+ DIRECT_IPC_SEM_CLIENT); -+ if (semerr < 0) { -+ SNDERR("SEMDOWN FAILED with err %d", semerr); -+ return semerr; -+ } -+ -+ if (snd_pcm_state(direct->spcm) != SND_PCM_STATE_XRUN) { -+ /* ignore... someone else already did recovery */ -+ semerr = snd_pcm_direct_semaphore_up(direct, -+ DIRECT_IPC_SEM_CLIENT); -+ if (semerr < 0) { -+ SNDERR("SEMUP FAILED with err %d", semerr); -+ return semerr; -+ } -+ return 0; -+ } -+ -+ ret = snd_pcm_prepare(direct->spcm); -+ if (ret < 0) { -+ SNDERR("recover: unable to prepare slave"); -+ semerr = snd_pcm_direct_semaphore_up(direct, -+ DIRECT_IPC_SEM_CLIENT); -+ if (semerr < 0) { -+ SNDERR("SEMUP FAILED with err %d", semerr); -+ return semerr; -+ } -+ return ret; -+ } -+ -+ if (direct->type == SND_PCM_TYPE_DSHARE) { -+ const snd_pcm_channel_area_t *dst_areas; -+ dst_areas = snd_pcm_mmap_areas(direct->spcm); -+ snd_pcm_areas_silence(dst_areas, 0, direct->spcm->channels, -+ direct->spcm->buffer_size, -+ direct->spcm->format); -+ } -+ -+ ret = snd_pcm_start(direct->spcm); -+ if (ret < 0) { -+ SNDERR("recover: unable to start slave"); -+ semerr = snd_pcm_direct_semaphore_up(direct, -+ DIRECT_IPC_SEM_CLIENT); -+ if (semerr < 0) { -+ SNDERR("SEMUP FAILED with err %d", semerr); -+ return semerr; -+ } -+ return ret; -+ } -+ direct->shmptr->recoveries++; -+ semerr = snd_pcm_direct_semaphore_up(direct, -+ DIRECT_IPC_SEM_CLIENT); -+ if (semerr < 0) { -+ SNDERR("SEMUP FAILED with err %d", semerr); -+ return semerr; -+ } -+ return 0; -+} -+ -+/* -+ * enter xrun state, if slave xrun occurred -+ * @return: 0 - no xrun >0: xrun happened -+ */ -+int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm) -+{ -+ if (direct->shmptr->recoveries != direct->recoveries) { -+ /* no matter how many xruns we missed - -+ * so don't increment but just update to actual counter -+ */ -+ direct->recoveries = direct->shmptr->recoveries; -+ pcm->fast_ops->drop(pcm); -+ /* trigger_tstamp update is missing in drop callbacks */ -+ gettimestamp(&direct->trigger_tstamp, pcm->tstamp_type); -+ /* no timer clear: -+ * if slave already entered xrun again the event is lost. -+ * snd_pcm_direct_clear_timer_queue(direct); -+ */ -+ direct->state = SND_PCM_STATE_XRUN; -+ return 1; -+ } -+ return 0; -+} -+ - int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) - { - snd_pcm_direct_t *dmix = pcm->private_data; -@@ -572,6 +667,12 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in - } - switch (snd_pcm_state(dmix->spcm)) { - case SND_PCM_STATE_XRUN: -+ /* recover slave and update client state to xrun -+ * before returning POLLERR -+ */ -+ snd_pcm_direct_slave_recover(dmix); -+ snd_pcm_direct_client_chk_xrun(dmix, pcm); -+ /* fallthrough */ - case SND_PCM_STATE_SUSPENDED: - case SND_PCM_STATE_SETUP: - events |= POLLERR; -@@ -1382,6 +1483,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm - dmix->slave_buffer_size = spcm->buffer_size; - dmix->slave_period_size = dmix->shmptr->s.period_size; - dmix->slave_boundary = spcm->boundary; -+ dmix->recoveries = dmix->shmptr->recoveries; - - ret = snd_pcm_mmap(spcm); - if (ret < 0) { -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index aee38c5..d48f6b4 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -66,6 +66,7 @@ typedef struct { - char socket_name[256]; /* name of communication socket */ - snd_pcm_type_t type; /* PCM type (currently only hw) */ - int use_server; -+ unsigned int recoveries; /* no of executed recoveries on slave*/ - struct { - unsigned int format; - snd_interval_t rate; -@@ -157,6 +158,7 @@ struct snd_pcm_direct { - int var_periodsize; /* allow variable period size if max_periods is != -1*/ - unsigned int channels; /* client's channels */ - unsigned int *bindings; -+ unsigned int recoveries; /* mirror of executed recoveries on slave */ - union { - struct { - int shmid_sum; /* IPC global sum ring buffer memory identification */ -@@ -324,7 +326,8 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm - snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm); - snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm); - int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); -- -+int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct); -+int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm); - int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); - struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); - -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 0ab7323..f72ee67 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -434,15 +434,21 @@ static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr - static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dmix = pcm->private_data; -+ int err; - - switch (snd_pcm_state(dmix->spcm)) { - case SND_PCM_STATE_DISCONNECTED: - dmix->state = SND_PCM_STATE_DISCONNECTED; - return -ENODEV; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) -+ return err; -+ break; - default: - break; - } -- -+ if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) -+ return -EPIPE; - if (dmix->slowptr) - snd_pcm_hwsync(dmix->spcm); - -@@ -828,12 +834,16 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, - - switch (snd_pcm_state(dmix->spcm)) { - case SND_PCM_STATE_XRUN: -- return -EPIPE; -+ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) -+ return err; -+ break; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - default: - break; - } -+ if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) -+ return -EPIPE; - if (! size) - return 0; - snd_pcm_mmap_appl_forward(pcm, size); -@@ -841,8 +851,10 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, - if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) - return err; - } else if (dmix->state == SND_PCM_STATE_RUNNING || -- dmix->state == SND_PCM_STATE_DRAINING) -- snd_pcm_dmix_sync_ptr(pcm); -+ dmix->state == SND_PCM_STATE_DRAINING) { -+ if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) -+ return err; -+ } - if (dmix->state == SND_PCM_STATE_RUNNING || - dmix->state == SND_PCM_STATE_DRAINING) { - /* ok, we commit the changes after the validation of area */ -@@ -858,10 +870,13 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, - static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dmix = pcm->private_data; -+ int err; - - if (dmix->state == SND_PCM_STATE_RUNNING || -- dmix->state == SND_PCM_STATE_DRAINING) -- snd_pcm_dmix_sync_ptr(pcm); -+ dmix->state == SND_PCM_STATE_DRAINING) { -+ if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) -+ return err; -+ } - return snd_pcm_mmap_playback_avail(pcm); - } - -diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c -index a1fed5d..0d80037 100644 ---- a/src/pcm/pcm_dshare.c -+++ b/src/pcm/pcm_dshare.c -@@ -162,7 +162,7 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p - snd_pcm_direct_t *dshare = pcm->private_data; - snd_pcm_uframes_t old_slave_hw_ptr, avail; - snd_pcm_sframes_t diff; -- -+ - old_slave_hw_ptr = dshare->slave_hw_ptr; - dshare->slave_hw_ptr = slave_hw_ptr; - diff = slave_hw_ptr - old_slave_hw_ptr; -@@ -202,15 +202,21 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p - static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dshare = pcm->private_data; -+ int err; - - switch (snd_pcm_state(dshare->spcm)) { - case SND_PCM_STATE_DISCONNECTED: - dshare->state = SNDRV_PCM_STATE_DISCONNECTED; - return -ENODEV; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) -+ return err; -+ break; - default: - break; - } -- -+ if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) -+ return -EPIPE; - if (dshare->slowptr) - snd_pcm_hwsync(dshare->spcm); - -@@ -516,12 +522,16 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, - - switch (snd_pcm_state(dshare->spcm)) { - case SND_PCM_STATE_XRUN: -- return -EPIPE; -+ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) -+ return err; -+ break; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - default: - break; - } -+ if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) -+ return -EPIPE; - if (! size) - return 0; - snd_pcm_mmap_appl_forward(pcm, size); -@@ -529,8 +539,10 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, - if ((err = snd_pcm_dshare_start_timer(dshare)) < 0) - return err; - } else if (dshare->state == SND_PCM_STATE_RUNNING || -- dshare->state == SND_PCM_STATE_DRAINING) -- snd_pcm_dshare_sync_ptr(pcm); -+ dshare->state == SND_PCM_STATE_DRAINING) { -+ if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) -+ return err; -+ } - if (dshare->state == SND_PCM_STATE_RUNNING || - dshare->state == SND_PCM_STATE_DRAINING) { - /* ok, we commit the changes after the validation of area */ -@@ -546,10 +558,13 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, - static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dshare = pcm->private_data; -+ int err; - - if (dshare->state == SND_PCM_STATE_RUNNING || -- dshare->state == SND_PCM_STATE_DRAINING) -- snd_pcm_dshare_sync_ptr(pcm); -+ dshare->state == SND_PCM_STATE_DRAINING) { -+ if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) -+ return err; -+ } - return snd_pcm_mmap_playback_avail(pcm); - } - -diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c -index 85f0ff4..618d469 100644 ---- a/src/pcm/pcm_dsnoop.c -+++ b/src/pcm/pcm_dsnoop.c -@@ -132,14 +132,21 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) - snd_pcm_direct_t *dsnoop = pcm->private_data; - snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; - snd_pcm_sframes_t diff; -- -+ int err; -+ - switch (snd_pcm_state(dsnoop->spcm)) { - case SND_PCM_STATE_DISCONNECTED: - dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED; - return -ENODEV; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) -+ return err; -+ break; - default: - break; - } -+ if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) -+ return -EPIPE; - if (dsnoop->slowptr) - snd_pcm_hwsync(dsnoop->spcm); - old_slave_hw_ptr = dsnoop->slave_hw_ptr; -@@ -410,12 +417,16 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm, - - switch (snd_pcm_state(dsnoop->spcm)) { - case SND_PCM_STATE_XRUN: -- return -EPIPE; -+ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) -+ return err; -+ break; - case SND_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - default: - break; - } -+ if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) -+ return -EPIPE; - if (dsnoop->state == SND_PCM_STATE_RUNNING) { - err = snd_pcm_dsnoop_sync_ptr(pcm); - if (err < 0) --- -2.9.3 - - -From 789ee39727a12d6573b4d79e9cd7a375e6b8b005 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Tue, 10 Jan 2017 12:03:54 +0530 -Subject: [PATCH 12/37] pcm: direct: check state before enter poll on timer - -To avoid the chances of timeout, we need to check the enter poll -in state xrun. - -Signed-off-by: Andreas Pape -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 40 ++++++++++++++++++++++++++++++++++++++++ - src/pcm/pcm_direct.h | 2 ++ - src/pcm/pcm_dmix.c | 9 +++++++-- - src/pcm/pcm_dshare.c | 9 +++++++-- - src/pcm/pcm_dsnoop.c | 9 +++++++-- - 5 files changed, 63 insertions(+), 6 deletions(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index a512dd2..f4d7c3f 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -645,6 +645,46 @@ int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm) - return 0; - } - -+/* -+ * This is the only operation guaranteed to be called before entering poll(). -+ * Direct plugins use fd of snd_timer to poll on, these timers do NOT check -+ * state of substream in kernel by intention. -+ * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP). -+ * If xrun event was not correctly handled or was ignored it will never be -+ * evaluated again afterwards. -+ * This will result in snd_pcm_wait() always returning timeout. -+ * In contrast poll() on pcm hardware checks ALSA state and will immediately -+ * return POLLERR on XRUN. -+ * -+ * To prevent timeout and applications endlessly spinning without xrun -+ * detected we add a state check here which may trigger the xrun sequence. -+ * -+ * return count of filled descriptors or negative error code -+ */ -+int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, -+ unsigned int space) -+{ -+ if (pcm->poll_fd < 0) { -+ SNDMSG("poll_fd < 0"); -+ return -EIO; -+ } -+ if (space >= 1 && pfds) { -+ pfds->fd = pcm->poll_fd; -+ pfds->events = pcm->poll_events | POLLERR | POLLNVAL; -+ } else { -+ return 0; -+ } -+ -+ /* this will also evaluate slave state and enter xrun if necessary */ -+ switch (snd_pcm_state(pcm)) { -+ case SND_PCM_STATE_XRUN: -+ return -EPIPE; -+ default: -+ break; -+ } -+ return 1; -+} -+ - int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) - { - snd_pcm_direct_t *dmix = pcm->private_data; -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index d48f6b4..66107ec 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -307,6 +307,8 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, - snd_config_t *cfg); - int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock); - int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid); -+int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, -+ unsigned int space); - int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); - int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info); - int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index f72ee67..6664210 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -462,17 +462,22 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) - static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dmix = pcm->private_data; -+ int err; - snd_pcm_state_t state; - state = snd_pcm_state(dmix->spcm); - switch (state) { -- case SND_PCM_STATE_XRUN: - case SND_PCM_STATE_SUSPENDED: - case SND_PCM_STATE_DISCONNECTED: - dmix->state = state; - return state; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) -+ return err; -+ break; - default: - break; - } -+ snd_pcm_direct_client_chk_xrun(dmix, pcm); - if (dmix->state == STATE_RUN_PENDING) - return SNDRV_PCM_STATE_RUNNING; - return dmix->state; -@@ -968,7 +973,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { - .avail_update = snd_pcm_dmix_avail_update, - .mmap_commit = snd_pcm_dmix_mmap_commit, - .htimestamp = snd_pcm_dmix_htimestamp, -- .poll_descriptors = NULL, -+ .poll_descriptors = snd_pcm_direct_poll_descriptors, - .poll_descriptors_count = NULL, - .poll_revents = snd_pcm_dmix_poll_revents, - }; -diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c -index 0d80037..fdc95e3 100644 ---- a/src/pcm/pcm_dshare.c -+++ b/src/pcm/pcm_dshare.c -@@ -255,17 +255,22 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dshare = pcm->private_data; -+ int err; - snd_pcm_state_t state; - state = snd_pcm_state(dshare->spcm); - switch (state) { -- case SND_PCM_STATE_XRUN: - case SND_PCM_STATE_SUSPENDED: - case SND_PCM_STATE_DISCONNECTED: - dshare->state = state; - return state; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) -+ return err; -+ break; - default: - break; - } -+ snd_pcm_direct_client_chk_xrun(dshare, pcm); - if (dshare->state == STATE_RUN_PENDING) - return SNDRV_PCM_STATE_RUNNING; - return dshare->state; -@@ -646,7 +651,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { - .avail_update = snd_pcm_dshare_avail_update, - .mmap_commit = snd_pcm_dshare_mmap_commit, - .htimestamp = snd_pcm_dshare_htimestamp, -- .poll_descriptors = NULL, -+ .poll_descriptors = snd_pcm_direct_poll_descriptors, - .poll_descriptors_count = NULL, - .poll_revents = snd_pcm_direct_poll_revents, - }; -diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c -index 618d469..a148771 100644 ---- a/src/pcm/pcm_dsnoop.c -+++ b/src/pcm/pcm_dsnoop.c -@@ -208,17 +208,22 @@ static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm) - { - snd_pcm_direct_t *dsnoop = pcm->private_data; -+ int err; - snd_pcm_state_t state; - state = snd_pcm_state(dsnoop->spcm); - switch (state) { -- case SND_PCM_STATE_XRUN: - case SND_PCM_STATE_SUSPENDED: - case SND_PCM_STATE_DISCONNECTED: - dsnoop->state = state; - return state; -+ case SND_PCM_STATE_XRUN: -+ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) -+ return err; -+ break; - default: - break; - } -+ snd_pcm_direct_client_chk_xrun(dsnoop, pcm); - return dsnoop->state; - } - -@@ -531,7 +536,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { - .avail_update = snd_pcm_dsnoop_avail_update, - .mmap_commit = snd_pcm_dsnoop_mmap_commit, - .htimestamp = snd_pcm_dsnoop_htimestamp, -- .poll_descriptors = NULL, -+ .poll_descriptors = snd_pcm_direct_poll_descriptors, - .poll_descriptors_count = NULL, - .poll_revents = snd_pcm_direct_poll_revents, - }; --- -2.9.3 - - -From 79a358ae26f74ed9b92b2190d4725325edf0c787 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Tue, 10 Jan 2017 12:04:09 +0530 -Subject: [PATCH 13/37] pcm: direct: don't return bogus buffer levels in xrun - state - -Signed-off-by: Andreas Pape -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_dmix.c | 3 +++ - src/pcm/pcm_dshare.c | 3 +++ - src/pcm/pcm_dsnoop.c | 3 +++ - 3 files changed, 9 insertions(+) - -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 6664210..2ef6159 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -882,6 +882,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) - if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) - return err; - } -+ if (dmix->state == SND_PCM_STATE_XRUN) -+ return -EPIPE; -+ - return snd_pcm_mmap_playback_avail(pcm); - } - -diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c -index fdc95e3..331f799 100644 ---- a/src/pcm/pcm_dshare.c -+++ b/src/pcm/pcm_dshare.c -@@ -570,6 +570,9 @@ static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) - if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) - return err; - } -+ if (dshare->state == SND_PCM_STATE_XRUN) -+ return -EPIPE; -+ - return snd_pcm_mmap_playback_avail(pcm); - } - -diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c -index a148771..539b671 100644 ---- a/src/pcm/pcm_dsnoop.c -+++ b/src/pcm/pcm_dsnoop.c -@@ -454,6 +454,9 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm) - if (err < 0) - return err; - } -+ if (dsnoop->state == SND_PCM_STATE_XRUN) -+ return -EPIPE; -+ - return snd_pcm_mmap_capture_avail(pcm); - } - --- -2.9.3 - - -From 360c976aaa051809c34cb412ffa52380baeaabee Mon Sep 17 00:00:00 2001 -From: Vinod Koul -Date: Thu, 12 Jan 2017 14:50:28 +0530 -Subject: [PATCH 14/37] conf/ucm: broxton: add broxton-rt298 conf files - -This adds the UCM conf files for broxton enabling with rt298 codec on -I2S audio, HDMI and DMIC ports. - -Signed-off-by: Nishit Sharma -Signed-off-by: G Kranthi -Signed-off-by: Vinod Koul -Signed-off-by: Takashi Iwai ---- - configure.ac | 1 + - src/conf/ucm/Makefile.am | 2 +- - src/conf/ucm/broxton-rt298/Hdmi1 | 22 +++++ - src/conf/ucm/broxton-rt298/Hdmi2 | 14 +++ - src/conf/ucm/broxton-rt298/HiFi | 129 ++++++++++++++++++++++++++ - src/conf/ucm/broxton-rt298/Makefile.am | 4 + - src/conf/ucm/broxton-rt298/broxton-rt298.conf | 58 ++++++++++++ - 7 files changed, 229 insertions(+), 1 deletion(-) - create mode 100644 src/conf/ucm/broxton-rt298/Hdmi1 - create mode 100644 src/conf/ucm/broxton-rt298/Hdmi2 - create mode 100644 src/conf/ucm/broxton-rt298/HiFi - create mode 100644 src/conf/ucm/broxton-rt298/Makefile.am - create mode 100644 src/conf/ucm/broxton-rt298/broxton-rt298.conf - -diff --git a/configure.ac b/configure.ac -index 71bd852..d645ab6 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -684,6 +684,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ - src/conf/topology/bxtrt298/Makefile \ - alsalisp/Makefile aserver/Makefile \ - test/Makefile test/lsb/Makefile \ -+ src/conf/ucm/broxton-rt298/Makefile \ - utils/Makefile utils/alsa-lib.spec utils/alsa.pc) - - dnl Create asoundlib.h dynamically according to configure options -diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am -index a11d324..ea9b385 100644 ---- a/src/conf/ucm/Makefile.am -+++ b/src/conf/ucm/Makefile.am -@@ -1 +1 @@ --SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 skylake-rt286 VEYRON-I2S chtrt5645 DB410c -+SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 skylake-rt286 VEYRON-I2S chtrt5645 DB410c broxton-rt298 -diff --git a/src/conf/ucm/broxton-rt298/Hdmi1 b/src/conf/ucm/broxton-rt298/Hdmi1 -new file mode 100644 -index 0000000..48514f4 ---- /dev/null -+++ b/src/conf/ucm/broxton-rt298/Hdmi1 -@@ -0,0 +1,22 @@ -+# Usecase for device HDMI1/Display Port stereo playback on Intel SKYLAKE/KABYLAKE platforms -+# For Audio in I2S mode -+ -+SectionDevice."Hdmi1" { -+ Comment "HDMI/Display Port 1 Stereo" -+ -+ EnableSequence [ -+ exec "echo Hdmi1 EnableSequnece" -+ ] -+ -+ DisableSequence [ -+ exec "echo Hdmi1 DisableSequnece" -+ ] -+ -+ Value { -+ PlaybackPCM "hw:broxtonrt298,4" -+ PlaybackChannels "2" -+ PlaybackPriority "3" -+ JackControl "HDMI/DP, pcm=4 Jack" -+ } -+} -+ -diff --git a/src/conf/ucm/broxton-rt298/Hdmi2 b/src/conf/ucm/broxton-rt298/Hdmi2 -new file mode 100644 -index 0000000..764f8b9 ---- /dev/null -+++ b/src/conf/ucm/broxton-rt298/Hdmi2 -@@ -0,0 +1,14 @@ -+# Usecase for device HDMI2/Display Port stereo playback on Intel Broxton platforms -+# For Audio in I2S mode -+ -+SectionDevice."Hdmi2" { -+ Comment "HDMI/Display Port 2 Stereo" -+ -+ Value { -+ PlaybackPCM "hw:broxtonrt298,5" -+ PlaybackChannels "2" -+ PlaybackPriority "4" -+ JackControl "HDMI/DP, pcm=5 Jack" -+ } -+} -+ -diff --git a/src/conf/ucm/broxton-rt298/HiFi b/src/conf/ucm/broxton-rt298/HiFi -new file mode 100644 -index 0000000..2e2d6fe ---- /dev/null -+++ b/src/conf/ucm/broxton-rt298/HiFi -@@ -0,0 +1,129 @@ -+# Usecase for stereo playback Speaker and Headset, Recording on DMIC and Headset MIC. -+# For Audio in I2S mode on Intel Broxton platforms -+ -+SectionVerb { -+ -+ EnableSequence [ -+ cdev "hw:broxtonrt298" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" -+ ] -+ -+ DisableSequence [ -+ cdev "hw:broxtonrt298" -+ ] -+ -+ Value { -+ TQ "HiFi" -+ CapturePCM "hw:broxtonrt298,1" -+ PlaybackPCM "hw:broxtonrt298,0" -+ } -+} -+ -+SectionDevice."dmiccap" { -+ Comment "DMIC Stereo" -+ -+ ConflictingDevice [ -+ "Headset" -+ ] -+ -+ EnableSequence [ -+ -+ cdev "hw:broxtonrt298" -+ exec "echo broxtonrt298 dmiccap called" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" -+ cset "name='media0_out mo codec0_in mi Switch' 0" -+ cset "name='Mic Jack Switch' 0" -+ -+ ] -+ -+ DisableSequence [ -+ cdev "hw:broxtonrt298" -+ cset "name='media0_out mo codec0_in mi Switch' 1" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" -+ cset "name='Mic Jack Switch' 1" -+ cset "name='ADC 0 Mux' 0" -+ ] -+ Value { -+ CaptureChannels "2" -+ CapturePriority "2" -+ } -+} -+ -+SectionDevice."Headphones" { -+ Comment "Headphones" -+ -+ ConflictingDevice [ -+ "Speaker" -+ ] -+ EnableSequence [ -+ cdev "hw:broxtonrt298" -+ exec "echo broxtonrt298 Headphone called" -+ cset "name='HPO L Switch' 1" -+ cset "name='HPO R Switch' 1" -+ cset "name='Headphone Jack Switch' 1" -+ cset "name='Speaker Playback Switch' 0,0" -+ ] -+ -+ DisableSequence [ -+ cdev "hw:broxtonrt298" -+ ] -+ Value { -+ PlaybackChannels "2" -+ PlaybackPriority "1" -+ JackControl "Headphone Jack" -+ JackHWMute "Speaker" -+ } -+} -+ -+SectionDevice."Speaker" { -+ Comment "Speaker" -+ -+ ConflictingDevice [ -+ "Headphones" -+ ] -+ EnableSequence [ -+ cdev "hw:broxtonrt298" -+ exec "echo broxtonrt298 speaker called" -+ cset "name='SPO Switch' 1" -+ cset "name='Speaker Playback Switch' 1,1" -+ cset "name='Speaker Switch' 1" -+ cset "name='HPO L Switch' 0" -+ cset "name='HPO R Switch' 0" -+ ] -+ -+ DisableSequence [ -+ ] -+ Value { -+ PlaybackChannels "2" -+ PlaybackPriority "1" -+ JackHWMute "Headphones" -+ } -+} -+ -+SectionDevice."Headset" { -+ Comment "Headset Mic" -+ -+ ConflictingDevice [ -+ "dmiccap" -+ ] -+ EnableSequence [ -+ cdev "hw:broxtonrt298" -+ exec "echo broxtonrt298 Headset called" -+ cset "name='media0_out mo codec0_in mi Switch' 1" -+ cset "name='ADC0 Capture Volume' 105,105" -+ cset "name='ADC 0 Mux' 0" -+ cset "name='Mic Jack Switch' 1" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" -+ ] -+ -+ DisableSequence [ -+ cdev "hw:broxtonrt298" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" -+ cset "name='media0_out mo codec0_in mi Switch' 0" -+ ] -+ Value { -+ CaptureChannels "2" -+ CapturePriority "2" -+ JackControl "Mic Jack" -+ } -+} -diff --git a/src/conf/ucm/broxton-rt298/Makefile.am b/src/conf/ucm/broxton-rt298/Makefile.am -new file mode 100644 -index 0000000..80f480e ---- /dev/null -+++ b/src/conf/ucm/broxton-rt298/Makefile.am -@@ -0,0 +1,4 @@ -+alsaconfigdir = @ALSA_CONFIG_DIR@ -+ucmdir = $(alsaconfigdir)/ucm/broxton-rt298 -+ucm_DATA = broxton-rt298.conf HiFi Hdmi1 Hdmi2 -+EXTRA_DIST = $(ucm_DATA) -diff --git a/src/conf/ucm/broxton-rt298/broxton-rt298.conf b/src/conf/ucm/broxton-rt298/broxton-rt298.conf -new file mode 100644 -index 0000000..3f3d0be ---- /dev/null -+++ b/src/conf/ucm/broxton-rt298/broxton-rt298.conf -@@ -0,0 +1,58 @@ -+# UCM for Intel Broxton platforms -+# For Audio in I2S mode -+ -+SectionUseCase."HiFi" { -+ File "HiFi" -+ Comment "Play and record HiFi quality Music" -+} -+ -+SectionUseCase."Hdmi1" { -+ File "Hdmi1" -+ Comment "Play on Hdmi/DP 1" -+} -+ -+SectionUseCase."Hdmi2" { -+ File "Hdmi2" -+ Comment "Play on Hdmi/DP 2" -+} -+ -+ValueDefaults { -+ PlaybackCTL "hw:broxtonrt298" -+ CaptureCTL "hw:broxtonrt298" -+ CaptureChannels "2" -+ CapturePriority "2" -+} -+ -+SectionDefaults [ -+ cdev "hw:broxtonrt298" -+ exec "echo broxtonrt298 CONF Defaults" -+ cset "name='Headphone Jack Switch' 1" -+ cset "name='Speaker Switch' 1" -+ cset "name='Speaker Playback Switch' 0,0" -+ cset "name='Front DAC Switch' 1" -+ cset "name='Front RECMIX Switch' 0" -+ cset "name='Mic Jack Switch' 1" -+ cset "name='ADC 0 Mux' 2" -+ cset "name='ADC 1 Mux' 0" -+ cset "name='DAC0 Playback Volume' 100,100" -+ cset "name='HPO L Switch' 0" -+ cset "name='HPO Mux' 0" -+ cset "name='HPO R Switch' 0" -+ cset "name='Pin 5 Mux' 1" -+ cset "name='Pin 6 Mux' 2" -+ cset "name='Pin 7 Mux' 3" -+ cset "name='RECMIX Beep Switch' 0" -+ cset "name='RECMIX Line1 Switch' 0" -+ cset "name='RECMIX Mic1 Switch' 0" -+ cset "name='SPK Mux' 0" -+ cset "name='SPO Switch' 1" -+ cset "name='codec0_out mo codec0_in mi Switch' 0" -+ cset "name='codec0_out mo dmic01_hifi_in mi Switch' 0" -+ cset "name='codec0_out mo media0_in mi Switch' 1" -+ cset "name='codec1_out mo codec0_in mi Switch' 0" -+ cset "name='codec1_out mo dmic01_hifi_in mi Switch' 0" -+ cset "name='codec1_out mo media0_in mi Switch' 0" -+ cset "name='media0_out mo codec0_in mi Switch' 1" -+ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" -+ cset "name='media0_out mo media0_in mi Switch' 0" -+] --- -2.9.3 - - -From 24e63b75275e9c923c336b8dba3919b980e8f234 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Mon, 16 Jan 2017 16:21:52 +0100 -Subject: [PATCH 15/37] pcm: direct: Fix deadlock in poll_descriptors - -The recent change in PCM direct plugins to check XRUN in -poll_descriptors callback caused a regression; as consequence, the -whole playback hangs up. - -The culprit is a mutex dead lock by the call in snd_pcm_state() inside -the new snd_pcm_direct_poll_descriptors(). The poll_descriptors code -path is protected with pcm mutex, thus an unlocked version -(__snd_pcm_state()) has to be used inside the callback instead. - -Fixes: 789ee39727a1 ("pcm: direct: check state before enter poll on timer") -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index f4d7c3f..e4bef78 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -676,7 +676,8 @@ int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, - } - - /* this will also evaluate slave state and enter xrun if necessary */ -- switch (snd_pcm_state(pcm)) { -+ /* using __snd_pcm_state() since this function is called inside lock */ -+ switch (__snd_pcm_state(pcm)) { - case SND_PCM_STATE_XRUN: - return -EPIPE; - default: --- -2.9.3 - - -From 2b9b3f013467765219c8ab8a50943d3c7db68f75 Mon Sep 17 00:00:00 2001 -From: Mengdong Lin -Date: Wed, 18 Jan 2017 11:52:35 +0800 -Subject: [PATCH 16/37] ucm: Assure the user input card name not to exceed max - size of card long name - -Users can load a card's UCM configuration file by giving the card short -name or long name, which should not exceed the maximum card long name -defined by the kernel. The kernel uses an 80-character buffer to store -the card long name. - -Signed-off-by: Mengdong Lin -Signed-off-by: Takashi Iwai ---- - src/ucm/parser.c | 6 ++++++ - src/ucm/ucm_local.h | 1 + - 2 files changed, 7 insertions(+) - -diff --git a/src/ucm/parser.c b/src/ucm/parser.c -index f520abc..f61201a 100644 ---- a/src/ucm/parser.c -+++ b/src/ucm/parser.c -@@ -1335,6 +1335,12 @@ static int load_master_config(const char *card_name, snd_config_t **cfg) - char *env = getenv(ALSA_CONFIG_UCM_VAR); - int err; - -+ if (strnlen(card_name, MAX_CARD_LONG_NAME) == MAX_CARD_LONG_NAME) { -+ uc_error("error: invalid card name %s (at most %d chars)\n", -+ card_name, MAX_CARD_LONG_NAME - 1); -+ return -EINVAL; -+ } -+ - snprintf(filename, sizeof(filename)-1, - "%s/%s/%s.conf", env ? env : ALSA_USE_CASE_DIR, - card_name, card_name); -diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h -index 6d3302f..e41aafa 100644 ---- a/src/ucm/ucm_local.h -+++ b/src/ucm/ucm_local.h -@@ -41,6 +41,7 @@ - #include "use-case.h" - - #define MAX_FILE 256 -+#define MAX_CARD_LONG_NAME 80 - #define ALSA_USE_CASE_DIR ALSA_CONFIG_DIR "/ucm" - - #define SEQUENCE_ELEMENT_TYPE_CDEV 1 --- -2.9.3 - - -From 4b9297e65f541f1a6c1b4a036f66936b9cafe030 Mon Sep 17 00:00:00 2001 -From: Mengdong Lin -Date: Wed, 18 Jan 2017 11:53:35 +0800 -Subject: [PATCH 17/37] ucm: Load device-specific configuration file based on - the card long name - -Intel DSP platform drivers are used by many different devices. For user -space to differentiate them, ASoC machine drivers may use the DMI info -(vendor-product-version-board) as card long name. Possible card long names -are: -DellInc.-XPS139343-01-0310JH -ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA -Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX -... - -If we want to define a device-specific UCM config file for a card, we -need to use the card long name as the name of both the directory that -contains the UCM config file and the UCM config file itself, like -longname/longname.conf - -When being asked to load configuration file of a card, UCM will try to -find the card in the local machine and get its long name. If the card -long name is available, try to load the file longname/longname.conf to -get the best device-specific configuration; if this file is not available, -fall back to load the default configuration file shortname/shortname.conf -as before. - -This update is backward compatible, because if ASoC machine drivers don't -explicity use DMI or other means to set the card long name, ASoC core -will use the card short name as the long name. And so UCM will load the -config file that matches both the card short name and the long name. - -Signed-off-by: Mengdong Lin -Signed-off-by: Takashi Iwai ---- - src/ucm/parser.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++--- - src/ucm/ucm_local.h | 2 ++ - 2 files changed, 97 insertions(+), 4 deletions(-) - -diff --git a/src/ucm/parser.c b/src/ucm/parser.c -index f61201a..798bf48 100644 ---- a/src/ucm/parser.c -+++ b/src/ucm/parser.c -@@ -56,6 +56,9 @@ static const char * const component_dir[] = { - NULL, /* terminator */ - }; - -+static int filename_filter(const struct dirent *dirent); -+static int is_component_directory(const char *dir); -+ - static int parse_sequence(snd_use_case_mgr_t *uc_mgr, - struct list_head *base, - snd_config_t *cfg); -@@ -1329,6 +1332,66 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) - return 0; - } - -+/* find the card in the local machine and store the card long name */ -+static int get_card_long_name(snd_use_case_mgr_t *mgr) -+{ -+ const char *card_name = mgr->card_name; -+ snd_ctl_t *handle; -+ int card, err; -+ snd_ctl_card_info_t *info; -+ const char *_name, *_long_name; -+ -+ snd_ctl_card_info_alloca(&info); -+ -+ card = -1; -+ if (snd_card_next(&card) < 0 || card < 0) { -+ uc_error("no soundcards found..."); -+ return -1; -+ } -+ -+ while (card >= 0) { -+ char name[32]; -+ -+ sprintf(name, "hw:%d", card); -+ err = snd_ctl_open(&handle, name, 0); -+ if (err < 0) { -+ uc_error("control open (%i): %s", card, -+ snd_strerror(err)); -+ goto next_card; -+ } -+ -+ err = snd_ctl_card_info(handle, info); -+ if (err < 0) { -+ uc_error("control hardware info (%i): %s", card, -+ snd_strerror(err)); -+ snd_ctl_close(handle); -+ goto next_card; -+ } -+ -+ /* Find the local card by comparing the given name with the -+ * card short name and long name. The given card name may be -+ * either a short name or long name, because users may open -+ * the card by either of the two names. -+ */ -+ _name = snd_ctl_card_info_get_name(info); -+ _long_name = snd_ctl_card_info_get_longname(info); -+ if (!strcmp(card_name, _name) -+ || !strcmp(card_name, _long_name)) { -+ strcpy(mgr->card_long_name, _long_name); -+ snd_ctl_close(handle); -+ return 0; -+ } -+ -+ snd_ctl_close(handle); -+next_card: -+ if (snd_card_next(&card) < 0) { -+ uc_error("snd_card_next"); -+ break; -+ } -+ } -+ -+ return -1; -+} - static int load_master_config(const char *card_name, snd_config_t **cfg) - { - char filename[MAX_FILE]; -@@ -1356,15 +1419,43 @@ static int load_master_config(const char *card_name, snd_config_t **cfg) - return 0; - } - --/* load master use case file for sound card */ -+/* load master use case file for sound card -+ * -+ * The same ASoC machine driver can be shared by many different devices. -+ * For user space to differentiate them and get the best device-specific -+ * configuration, ASoC machine drivers may use the DMI info -+ * (vendor-product-version-board) as the card long name. And user space can -+ * define configuration files like longnamei/longname.conf for a specific device. -+ * -+ * This function will try to find the card in the local machine and get its -+ * long name, then load the file longname/longname.conf to get the best -+ * device-specific configuration. If the card is not found in the local -+ * machine or the device-specific file is not available, fall back to load -+ * the default configuration file name/name.conf. -+ */ - int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) - { - snd_config_t *cfg; - int err; - -- err = load_master_config(uc_mgr->card_name, &cfg); -- if (err < 0) -- return err; -+ err = get_card_long_name(uc_mgr); -+ if (err == 0) /* load file that maches the card long name */ -+ err = load_master_config(uc_mgr->card_long_name, &cfg); -+ -+ if (err == 0) { -+ /* got device-specific file that matches the card long name */ -+ strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name); -+ } else { -+ /* Fall back to the file that maches the given card name, -+ * either short name or long name (users may open a card by -+ * its name or long name). -+ */ -+ err = load_master_config(uc_mgr->card_name, &cfg); -+ if (err < 0) -+ return err; -+ strcpy(uc_mgr->conf_file_name, uc_mgr->card_name); -+ } -+ - err = parse_master_file(uc_mgr, cfg); - snd_config_delete(cfg); - if (err < 0) -diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h -index e41aafa..299a5b9 100644 ---- a/src/ucm/ucm_local.h -+++ b/src/ucm/ucm_local.h -@@ -191,6 +191,8 @@ struct use_case_verb { - */ - struct snd_use_case_mgr { - char *card_name; -+ char card_long_name[MAX_CARD_LONG_NAME]; -+ char conf_file_name[MAX_CARD_LONG_NAME]; - char *comment; - - /* use case verb, devices and modifier configs parsed from files */ --- -2.9.3 - - -From e93d93a8cd37f94f119aba72ca05d7f92b648bcc Mon Sep 17 00:00:00 2001 -From: Mengdong Lin -Date: Wed, 18 Jan 2017 11:53:42 +0800 -Subject: [PATCH 18/37] ucm: Add command 'get _file' to get the config file - name of the opened card - -After opening a card, this command can show the name of the actually -loaded configuration file, either matches the card name or card long name. -So developers can check if there is a device-sepcific configuration file -available for a given card. - -Signed-off-by: Mengdong Lin -Signed-off-by: Takashi Iwai ---- - include/use-case.h | 1 + - src/ucm/main.c | 14 ++++++++++++++ - 2 files changed, 15 insertions(+) - -diff --git a/include/use-case.h b/include/use-case.h -index 8911645..ae22bde 100644 ---- a/include/use-case.h -+++ b/include/use-case.h -@@ -230,6 +230,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, - * Known identifiers: - * - NULL - return current card - * - _verb - return current verb -+ * - _file - return configuration file loaded for current card - * - * - [=]{NAME}[/[{modifier}|{/device}][/{verb}]] - * - value identifier {NAME} -diff --git a/src/ucm/main.c b/src/ucm/main.c -index 38a5e81..2d33886 100644 ---- a/src/ucm/main.c -+++ b/src/ucm/main.c -@@ -1528,6 +1528,20 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, - goto __end; - } - err = 0; -+ } else if (strcmp(identifier, "_file") == 0) { -+ /* get the conf file name of the opened card */ -+ if ((uc_mgr->card_name == NULL) -+ || (uc_mgr->conf_file_name[0] == '\0')) { -+ err = -ENOENT; -+ goto __end; -+ } -+ *value = strndup(uc_mgr->conf_file_name, MAX_FILE); -+ if (*value == NULL) { -+ err = -ENOMEM; -+ goto __end; -+ } -+ err = 0; -+ - } else if (identifier[0] == '_') { - err = -ENOENT; - goto __end; --- -2.9.3 - - -From ec40aafa4374f2388876702513c4b3eee2e2235f Mon Sep 17 00:00:00 2001 -From: Liam Girdwood -Date: Tue, 24 Jan 2017 14:59:08 +0000 -Subject: [PATCH 19/37] topology: Fix incorrect license in source comments. - -The topology source files had the wrong licence specified in the -comments when initially upstreamed. The topology source files are all -licensed under the LGPL-2.1 and not the GPLv2. - -All earlier versions of the alsa-lib topology source files must be -considered LGPL-2.1 like the other source files in alsa-lib and also -as specified in the alsa-lib COPYING file. - -Signed-off-by: Liam Girdwood -Signed-off-by: Takashi Iwai ---- - src/topology/builder.c | 17 +++++++++-------- - src/topology/channel.c | 17 +++++++++-------- - src/topology/ctl.c | 17 +++++++++-------- - src/topology/dapm.c | 17 +++++++++-------- - src/topology/data.c | 17 +++++++++-------- - src/topology/elem.c | 17 +++++++++-------- - src/topology/ops.c | 17 +++++++++-------- - src/topology/parser.c | 17 +++++++++-------- - src/topology/pcm.c | 17 +++++++++-------- - src/topology/text.c | 17 +++++++++-------- - 10 files changed, 90 insertions(+), 80 deletions(-) - -diff --git a/src/topology/builder.c b/src/topology/builder.c -index 20fa925..dcd9e2a 100644 ---- a/src/topology/builder.c -+++ b/src/topology/builder.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/channel.c b/src/topology/channel.c -index c2f1fea..8516b23 100644 ---- a/src/topology/channel.c -+++ b/src/topology/channel.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/ctl.c b/src/topology/ctl.c -index 907a97f..1da3d18 100644 ---- a/src/topology/ctl.c -+++ b/src/topology/ctl.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/dapm.c b/src/topology/dapm.c -index 8c585a7..eef72bb 100644 ---- a/src/topology/dapm.c -+++ b/src/topology/dapm.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/data.c b/src/topology/data.c -index 0d5c430..e2aa38c 100644 ---- a/src/topology/data.c -+++ b/src/topology/data.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/elem.c b/src/topology/elem.c -index db26483..efcf3e9 100644 ---- a/src/topology/elem.c -+++ b/src/topology/elem.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/ops.c b/src/topology/ops.c -index 1b5c1e2..6f8dc1f 100644 ---- a/src/topology/ops.c -+++ b/src/topology/ops.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/parser.c b/src/topology/parser.c -index c5f9757..cfc20e0 100644 ---- a/src/topology/parser.c -+++ b/src/topology/parser.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/pcm.c b/src/topology/pcm.c -index 8f8a703..5568d57 100644 ---- a/src/topology/pcm.c -+++ b/src/topology/pcm.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin -diff --git a/src/topology/text.c b/src/topology/text.c -index 303fbeb..cba6887 100644 ---- a/src/topology/text.c -+++ b/src/topology/text.c -@@ -2,14 +2,15 @@ - Copyright(c) 2014-2015 Intel Corporation - All rights reserved. - -- This program is free software; you can redistribute it and/or modify -- it under the terms of version 2 of the GNU General Public License as -- published by the Free Software Foundation. -- -- This program is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- General Public License for more details. -+ This library is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of -+ the License, or (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. - - Authors: Mengdong Lin - Yao Jin --- -2.9.3 - - -From 4dfa8f08fb834f7b087f35f9ba1746cd0c989d02 Mon Sep 17 00:00:00 2001 -From: Manohar Narkhede -Date: Wed, 25 Jan 2017 22:14:15 +0100 -Subject: [PATCH 20/37] conf/cards: add support for pistachio-card. - -The data sheet of the chip and technical reference manual can be found at https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.pdf -and https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf. - -The additional information about the cards can be found in src/conf/cards/pistachio-card.conf file. - -Signed-off-by: Manohar Narkhede -Signed-off-by: Takashi Iwai ---- - src/conf/cards/Makefile.am | 1 + - src/conf/cards/aliases.conf | 1 + - src/conf/cards/pistachio-card.conf | 58 ++++++++++++++++++++++++++++++++++++++ - 3 files changed, 60 insertions(+) - create mode 100644 src/conf/cards/pistachio-card.conf - -diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am -index 008d399..60b5309 100644 ---- a/src/conf/cards/Makefile.am -+++ b/src/conf/cards/Makefile.am -@@ -39,6 +39,7 @@ cfg_files = aliases.conf \ - Maestro3.conf \ - NFORCE.conf \ - PC-Speaker.conf \ -+ pistachio-card.conf \ - PMac.conf \ - PMacToonie.conf \ - PS3.conf \ -diff --git a/src/conf/cards/aliases.conf b/src/conf/cards/aliases.conf -index 4a92fb2..60f9d26 100644 ---- a/src/conf/cards/aliases.conf -+++ b/src/conf/cards/aliases.conf -@@ -55,6 +55,7 @@ AV100 cards.CMI8788 - AV200 cards.CMI8788 - CMI8786 cards.CMI8788 - CMI8787 cards.CMI8788 -+pistachio cards.pistachio-card - - - -diff --git a/src/conf/cards/pistachio-card.conf b/src/conf/cards/pistachio-card.conf -new file mode 100644 -index 0000000..59cd920 ---- /dev/null -+++ b/src/conf/cards/pistachio-card.conf -@@ -0,0 +1,58 @@ -+# -+# Configuration for the pistachio chip. -+# -+# The data sheet of the chip and technical reference manual can be -+found at -+https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.p -+df # and -+https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf. -+# -+# The list of hardware devices is as per below: -+# -+# root@OpenWrt:/# arecord -l -+# **** List of CAPTURE Hardware Devices **** card 0: pistachiocard [pistachio-card], device 1: pistachio-spdif-in snd-soc-dummy-dai-1 [] -+# Subdevices: 1/1 -+# Subdevice #0: subdevice #0 -+# card 0: pistachiocard [pistachio-card], device 4: pistachio-i2s-in-0 snd-soc-dummy-dai-4 [] -+# Subdevices: 1/1 -+# Subdevice #0: subdevice #0 -+# -+# root@OpenWrt:/# aplay -l -+# **** List of PLAYBACK Hardware Devices **** card 0: pistachiocard [pistachio-card], device 0: pistachio-spdif-out snd-soc-dummy-dai-0 [] -+# Subdevices: 1/1 -+# Subdevice #0: subdevice #0 -+# card 0: pistachiocard [pistachio-card], device 2: pistachio-parallel-out pistachio_internal_dac-2 [] -+# Subdevices: 1/1 -+# Subdevice #0: subdevice #0 -+# card 0: pistachiocard [pistachio-card], device 3: pistachio-i2s-out snd-soc-dummy-dai-3 [] -+# Subdevices: 1/1 -+# Subdevice #0: subdevice #0 -+# -+ -+pistachio-card.pcm.default{ -+ @args [ CARD ] -+ @args.CARD { -+ type string -+ default "pistachio" -+ } -+ @args.DEVICE { -+ type integer -+ default 2 -+ } -+ -+ type asym -+ capture.pcm { -+ type multi -+ slaves.a.pcm "hw:0,4" -+ slaves.a.channels 12 -+ bindings.0.slave a -+ bindings.0.channel 4 -+ bindings.1.slave a -+ bindings.1.channel 5 -+ } -+ -+ playback.pcm { -+ type hw -+ card $CARD -+ device $DEVICE -+ --- -2.9.3 - - -From e1143dd9ba350eb19d13d4e298eeb55179712a1e Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Fri, 27 Jan 2017 12:01:51 +0100 -Subject: [PATCH 21/37] pcm: multi: Drop the fixed slave_map[] in - snd_pcm_multi_open() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -slave_map[] in snd_pcm_multi_open() is a fixed size array and -obviously we have no overflow check, and eventually the program gets -an error when more than 64 channels are used. - -Although we can modify the code to allocate the array dynamically, it -turned out that we can drop the whole slave_map[] thingy in this -function when looking at the code closely. In the past, it was used -to identify the one-to-many mapping. But the check was dropped, and -now it's nothing more than a sanity check. - -Reported-by: Jörg Müller -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_multi.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c -index c4b1fba..9e4be71 100644 ---- a/src/pcm/pcm_multi.c -+++ b/src/pcm/pcm_multi.c -@@ -1015,7 +1015,6 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_multi_t *multi; - unsigned int i; - snd_pcm_stream_t stream; -- char slave_map[64][64] = { { 0 } }; - int err; - - assert(pcmp); -@@ -1059,8 +1058,6 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, - bind->slave_channel = schannels[i]; - if (sidxs[i] < 0) - continue; -- assert(!slave_map[sidxs[i]][schannels[i]]); -- slave_map[sidxs[i]][schannels[i]] = 1; - } - multi->channels_count = channels_count; - --- -2.9.3 - - -From 53dc36f1f465e2a1f9ed37906a7f16a438f941e4 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Tue, 7 Feb 2017 14:25:17 +0100 -Subject: [PATCH 22/37] conf: Add card config for Intel HDMI/DP LPE audio - -It's a playback-only device with a single PCM dedicated for HDMI/DP -output. The dmix is working with the latest driver code, so enable it -for default, while providing the hdmi PCM dev for the accesses with -AES bits. - -Signed-off-by: Takashi Iwai ---- - src/conf/cards/HdmiLpeAudio.conf | 85 ++++++++++++++++++++++++++++++++++++++++ - src/conf/cards/Makefile.am | 1 + - 2 files changed, 86 insertions(+) - create mode 100644 src/conf/cards/HdmiLpeAudio.conf - -diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf -new file mode 100644 -index 0000000..f5836c0 ---- /dev/null -+++ b/src/conf/cards/HdmiLpeAudio.conf -@@ -0,0 +1,85 @@ -+# -+# Configuration for the Intel HDMI/DP LPE audio -+# -+ -+ -+ -+HdmiLpeAudio.pcm.front.0 { -+ @args [ CARD ] -+ @args.CARD { -+ type string -+ } -+ type softvol -+ slave.pcm { -+ type hw -+ card $CARD -+ } -+ control { -+ name "PCM Playback Volume" -+ card $CARD -+ } -+} -+ -+# default with dmix+softvol -+HdmiLpeAudio.pcm.default { -+ @args [ CARD ] -+ @args.CARD { -+ type string -+ } -+ type plug -+ slave.pcm { -+ type softvol -+ slave.pcm { -+ @func concat -+ strings [ "dmix:" $CARD ] -+ } -+ control { -+ name "PCM Playback Volume" -+ card $CARD -+ } -+ } -+} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+HdmiLpeAudio.pcm.hdmi.0 { -+ @args [ CARD AES0 AES1 AES2 AES3 ] -+ @args.CARD { -+ type string -+ } -+ @args.AES0 { -+ type integer -+ } -+ @args.AES1 { -+ type integer -+ } -+ @args.AES2 { -+ type integer -+ } -+ @args.AES3 { -+ type integer -+ } -+ type hooks -+ slave.pcm { -+ type hw -+ card $CARD -+ } -+ hooks.0 { -+ type ctl_elems -+ hook_args [ -+ { -+ interface PCM -+ name "IEC958 Playback Default" -+ lock true -+ preserve true -+ value [ $AES0 $AES1 $AES2 $AES3 ] -+ } -+ ] -+ } -+} -diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am -index 60b5309..e8b530e 100644 ---- a/src/conf/cards/Makefile.am -+++ b/src/conf/cards/Makefile.am -@@ -30,6 +30,7 @@ cfg_files = aliases.conf \ - FireWave.conf \ - GUS.conf \ - HDA-Intel.conf \ -+ HdmiLpeAudio.conf \ - ICE1712.conf \ - ICE1724.conf \ - ICH.conf \ --- -2.9.3 - - -From b5a2c06f6c5d69fc71ef648af95a044ee1dc25d0 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Thu, 9 Feb 2017 17:23:22 +0100 -Subject: [PATCH 23/37] pcm: Avoid lock for snd_pcm_nonblock() - -snd_pcm_nonblock() is called as snd_pcm_abort(). Since -snd_pcm_abort() is called often from a signal handler to clean things -up (e.g. aplay does it), we may face a deadlock if the signal is -raised during the locked operation. - -There can be some way to check the deadlock state, but they would cost -much. Since the race condition of snd_pcm_nonblock() is quite small, -let's just drop the locking inside snd_pcm_nonblock() as a -workaround. - -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c -index 0cf740f..c136d55 100644 ---- a/src/pcm/pcm.c -+++ b/src/pcm/pcm.c -@@ -759,7 +759,10 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) - int err = 0; - - assert(pcm); -- __snd_pcm_lock(pcm); /* forced lock due to pcm field change */ -+ /* FIXME: __snd_pcm_lock() call below is commented out because of the -+ * the possible deadlock in signal handler calling snd_pcm_abort() -+ */ -+ /* __snd_pcm_lock(pcm); */ /* forced lock due to pcm field change */ - if ((err = pcm->ops->nonblock(pcm->op_arg, nonblock)) < 0) - goto unlock; - if (nonblock == 2) { -@@ -775,7 +778,7 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) - pcm->mode &= ~SND_PCM_NONBLOCK; - } - unlock: -- __snd_pcm_unlock(pcm); -+ /* __snd_pcm_unlock(pcm); */ /* FIXME: see above */ - return err; - } - --- -2.9.3 - - -From e31a3273df6eb619e35d10bf6a0fc0fded91d559 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Thu, 9 Feb 2017 17:29:21 +0100 -Subject: [PATCH 24/37] pcm: Disable locking in async mode - -When PCM is operated in async mode and an async handler calls some PCM -functions with lock during other PCM operations, we may hit a -deadlock. - -Although async mode is rarely used, it's still a possible use case. -Disable the locking when the stream is opened in async mode or it's -set to async mode via snd_pcm_async(). - -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c -index c136d55..493e903 100644 ---- a/src/pcm/pcm.c -+++ b/src/pcm/pcm.c -@@ -799,6 +799,8 @@ int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid) - sig = SIGIO; - if (pid == 0) - pid = getpid(); -+ /* async handler may lead to a deadlock; suppose no multi thread */ -+ pcm->lock_enabled = 0; - return pcm->ops->async(pcm->op_arg, sig, pid); - } - #endif -@@ -2597,7 +2599,10 @@ int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, - * each plugin may suppress this in its open call - */ - pcm->need_lock = 1; -- { -+ if (mode & SND_PCM_ASYNC) { -+ /* async handler may lead to a deadlock; suppose no MT */ -+ pcm->lock_enabled = 0; -+ } else { - /* set lock_enabled field depending on $LIBASOUND_THREAD_SAFE */ - static int do_lock_enable = -1; /* uninitialized */ - --- -2.9.3 - - -From 22eca6468b4aea47c783770ec0739d1e13bf3bfc Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Fri, 10 Feb 2017 12:16:12 +0100 -Subject: [PATCH 25/37] pcm: dmix: Allow disabling x86 optimizations - -The dmix plugin has some optimized implementations for x86 using the -direct memory accesses, which was rather the original version, in -addition to the "generic" implementation using the semaphore -blocking. The x86 implementation relies on the memory coherency *and* -the fast read/write on it. - -For other architectures, this has been always disabled just because of -memory coherency. But, the recent LPE audio development revealed -that, even on x86 platforms, the read/write performance might become -extremely bad when the buffer is marked as uncached. Some drivers -already know the buffer is uncached, we need to switch to the generic -mode in such a case. - -This patch introduces yet another flag to dmix configuration, -direct_memory_access, that indicates whether the x86-specific -optimization can be used or not. Each driver can set the flag in its -cards config namespace, and the default dmix config refers to it. - -As of this patch, only HDMI LPE Audio driver sets it. - -Signed-off-by: Takashi Iwai ---- - src/conf/cards/HdmiLpeAudio.conf | 3 +++ - src/conf/pcm/dmix.conf | 15 +++++++++++++++ - src/pcm/pcm_direct.c | 8 ++++++++ - src/pcm/pcm_direct.h | 2 ++ - src/pcm/pcm_dmix.c | 1 + - src/pcm/pcm_dmix_i386.c | 5 +++++ - src/pcm/pcm_dmix_x86_64.c | 5 +++++ - 7 files changed, 39 insertions(+) - -diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf -index f5836c0..61bdfea 100644 ---- a/src/conf/cards/HdmiLpeAudio.conf -+++ b/src/conf/cards/HdmiLpeAudio.conf -@@ -20,6 +20,9 @@ HdmiLpeAudio.pcm.front.0 { - } - } - -+# uncached memory reads have a high penalty -+HdmiLpeAudio.dmix.direct_memory_access false -+ - # default with dmix+softvol - HdmiLpeAudio.pcm.default { - @args [ CARD ] -diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf -index 7d0aa01..2d3b329 100644 ---- a/src/conf/pcm/dmix.conf -+++ b/src/conf/pcm/dmix.conf -@@ -49,6 +49,21 @@ pcm.!dmix { - @func refer - name defaults.pcm.ipc_perm - } -+ direct_memory_access { -+ @func refer -+ name { -+ @func concat -+ strings [ -+ "cards." -+ { -+ @func card_driver -+ card $CARD -+ } -+ ".dmix.direct_memory_access" -+ ] -+ } -+ default true -+ } - slave { - pcm { - type hw -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index e4bef78..364191b 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -1861,6 +1861,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, - rec->slowptr = 1; - rec->max_periods = 0; - rec->var_periodsize = 1; -+ rec->direct_memory_access = 1; - - /* read defaults */ - if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { -@@ -1974,6 +1975,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, - rec->var_periodsize = err; - continue; - } -+ if (strcmp(id, "direct_memory_access") == 0) { -+ err = snd_config_get_bool(n); -+ if (err < 0) -+ return err; -+ rec->direct_memory_access = err; -+ continue; -+ } - SNDERR("Unknown field %s", id); - return -EINVAL; - } -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index 66107ec..fba55fd 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -159,6 +159,7 @@ struct snd_pcm_direct { - unsigned int channels; /* client's channels */ - unsigned int *bindings; - unsigned int recoveries; /* mirror of executed recoveries on slave */ -+ int direct_memory_access; /* use arch-optimized buffer RW */ - union { - struct { - int shmid_sum; /* IPC global sum ring buffer memory identification */ -@@ -340,6 +341,7 @@ struct snd_pcm_direct_open_conf { - int slowptr; - int max_periods; - int var_periodsize; -+ int direct_memory_access; - snd_config_t *slave; - snd_config_t *bindings; - }; -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 2ef6159..dd0356e 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -1065,6 +1065,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, - dmix->max_periods = opts->max_periods; - dmix->var_periodsize = opts->var_periodsize; - dmix->sync_ptr = snd_pcm_dmix_sync_ptr; -+ dmix->direct_memory_access = opts->direct_memory_access; - - retry: - if (first_instance) { -diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c -index dcc6b9a..1ab983a 100644 ---- a/src/pcm/pcm_dmix_i386.c -+++ b/src/pcm/pcm_dmix_i386.c -@@ -87,6 +87,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) - { - static int smp = 0, mmx = 0, cmov = 0; - -+ if (!dmix->direct_memory_access) { -+ generic_mix_select_callbacks(dmix); -+ return; -+ } -+ - if (!((1ULL<< dmix->shmptr->s.format) & i386_dmix_supported_format)) { - generic_mix_select_callbacks(dmix); - return; -diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c -index 831046d..34c40d4 100644 ---- a/src/pcm/pcm_dmix_x86_64.c -+++ b/src/pcm/pcm_dmix_x86_64.c -@@ -70,6 +70,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) - { - static int smp = 0; - -+ if (!dmix->direct_memory_access) { -+ generic_mix_select_callbacks(dmix); -+ return; -+ } -+ - if (!((1ULL<< dmix->shmptr->s.format) & x86_64_dmix_supported_format)) { - generic_mix_select_callbacks(dmix); - return; --- -2.9.3 - - -From df7694d80cdd7d273b34ead6841b9f32f5991966 Mon Sep 17 00:00:00 2001 -From: Timo Wischer -Date: Fri, 17 Feb 2017 12:45:36 +0530 -Subject: [PATCH 26/37] pcm: dmix_rewind corrupts application pointer fix - -sometimes pulseaudio stops with the following assertion in libasound.so: -alsa-lib-1.0.29/src/pcm/pcm.c:2761: -snd_pcm_area_copy: Assertion `dst < src || dst >= src + bytes' failed. -Application pointer is handled properly, in cases of rewind operations. - -Signed-off-by: Timo Wischer -Signed-off-by: Ravikiran Polepalli -Signed-off-by: Mikhail Durnev -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_dmix.c | 33 +++++++++++++++++++++++---------- - 1 file changed, 23 insertions(+), 10 deletions(-) - -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index dd0356e..46142e5 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -706,7 +706,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f - { - snd_pcm_direct_t *dmix = pcm->private_data; - snd_pcm_uframes_t slave_appl_ptr, slave_size; -- snd_pcm_uframes_t appl_ptr, size, transfer, result; -+ snd_pcm_uframes_t appl_ptr, size, transfer, result, frames_to_remix; - int err; - const snd_pcm_channel_area_t *src_areas, *dst_areas; - -@@ -717,6 +717,13 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f - return err; - } - -+ /* (appl_ptr - last_appl_ptr) indicates the frames which are not -+ * already mixed -+ * (last_appl_ptr - hw_ptr) indicates the frames which are already -+ * mixed but not played yet. -+ * So they can be remixed. -+ */ -+ - if (dmix->last_appl_ptr < dmix->appl_ptr) - size = dmix->appl_ptr - dmix->last_appl_ptr; - else -@@ -729,6 +736,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f - return size; - result = size; - -+ /* 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 -@@ -741,9 +751,12 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f - slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr); - if (slave_size < size) - size = slave_size; -- frames -= size; -- result += size; -- -+ -+ /* frames which should be remixed will be saved -+ * to also backward the appl pointer on success -+ */ -+ frames_to_remix = size; -+ - /* add sample areas here */ - src_areas = snd_pcm_mmap_areas(pcm); - dst_areas = snd_pcm_mmap_areas(dmix->spcm); -@@ -769,15 +782,15 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f - appl_ptr += transfer; - appl_ptr %= pcm->buffer_size; - } -- dmix->last_appl_ptr -= frames; -- dmix->last_appl_ptr %= pcm->boundary; -- dmix->slave_appl_ptr -= frames; -- dmix->slave_appl_ptr %= dmix->slave_boundary; - dmix_up_sem(dmix); - -- snd_pcm_mmap_appl_backward(pcm, frames); -+ snd_pcm_mmap_appl_backward(pcm, frames_to_remix); -+ result += frames_to_remix; -+ /* At this point last_appl_ptr and appl_ptr has to indicate the -+ * position of the first not mixed frame -+ */ - -- return result + frames; -+ return result; - } - - static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm) --- -2.9.3 - - -From 9219034301a3bf3d8de57ac5672bbc1c53f18049 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Fri, 17 Feb 2017 12:45:56 +0530 -Subject: [PATCH 27/37] pcm: direct: fix race on clearing timer events - -snd_timer handling is racy: plugins clear timer queue if avail_min -is not reached to force a sleep on timer. The race can happen if -the expected event arrives in between the avail check and the -clearing of pending events. If this race happens, the user will -unnecessarily wait for one more timer event. On low latency/realtime -streams this can lead to xruns and must be avoided. - -As a fix we recheck avail after having cleared poll events. - -Signed-off-by: Andreas Pape -Signed-off-by: Jiada Wang -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_direct.c | 23 +++++++++++++++++++---- - src/pcm/pcm_direct.h | 2 +- - 2 files changed, 20 insertions(+), 5 deletions(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index 364191b..8a75c42 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -515,10 +515,12 @@ int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid) - } - - /* empty the timer read queue */ --void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) -+int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) - { -+ int changed = 0; - if (dmix->timer_need_poll) { - while (poll(&dmix->timer_fd, 1, 0) > 0) { -+ changed++; - /* we don't need the value */ - if (dmix->tread) { - snd_timer_tread_t rbuf[4]; -@@ -533,15 +535,17 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) - snd_timer_tread_t rbuf[4]; - int len; - while ((len = snd_timer_read(dmix->timer, rbuf, -- sizeof(rbuf))) > 0 && -+ sizeof(rbuf))) > 0 -+ && (++changed) && - len != sizeof(rbuf[0])) - ; - } else { - snd_timer_read_t rbuf; - while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0) -- ; -+ changed++; - } - } -+ return changed; - } - - int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) -@@ -693,6 +697,8 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in - int empty = 0; - - assert(pfds && nfds == 1 && revents); -+ -+timer_changed: - events = pfds[0].revents; - if (events & POLLIN) { - snd_pcm_uframes_t avail; -@@ -720,7 +726,16 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in - break; - default: - if (empty) { -- snd_pcm_direct_clear_timer_queue(dmix); -+ /* here we have a race condition: -+ * if period event arrived after the avail_update call -+ * above we might clear this event with the following -+ * clear_timer_queue. -+ * There is no way to do this in atomic manner, so we -+ * need to recheck avail_update if we successfully -+ * cleared a poll event. -+ */ -+ if (snd_pcm_direct_clear_timer_queue(dmix)) -+ goto timer_changed; - events &= ~(POLLOUT|POLLIN); - /* additional check */ - switch (__snd_pcm_state(pcm)) { -diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h -index fba55fd..24e85f0 100644 ---- a/src/pcm/pcm_direct.h -+++ b/src/pcm/pcm_direct.h -@@ -322,7 +322,7 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm); - int snd_pcm_direct_prepare(snd_pcm_t *pcm); - int snd_pcm_direct_resume(snd_pcm_t *pcm); - int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); --void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); -+int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); - int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); - int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); - --- -2.9.3 - - -From fe65b00f337dd08f8c14d54b0ce6b516424d78e8 Mon Sep 17 00:00:00 2001 -From: Timo Wischer -Date: Fri, 17 Feb 2017 12:47:17 +0530 -Subject: [PATCH 28/37] pcm: file: Enable file writing for capture path - -This commit reverts parts of commit 4081be0b87ab9fa53a8906e66bc240f18a7a9a54, -because it is realy useful to use the file plugin in a capture path for -debugging. Also it fixes the truncate issue mentioned in above commit. - -Additionally following MMAP access issue is considered: -$ arecord -D teeraw -M -d5 arecord.wav -Recording WAVE 'arecord.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono -ALSA lib pcm/pcm_file.c:358:(snd_pcm_file_write_bytes) -write failed: Bad file descriptor -ALSA lib pcm/pcm_file.c:358:(snd_pcm_file_write_bytes) -write failed: Bad file descriptor -arecord: pcm/pcm_file.c:397: snd_pcm_file_add_frames: -Assertion `file->wbuf_used_bytes < file->wbuf_size_bytes' failed. -Aborted by signal Aborted... - -Signed-off-by: Timo Wischer -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_file.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c -index 6d119d6..0363f84 100644 ---- a/src/pcm/pcm_file.c -+++ b/src/pcm/pcm_file.c -@@ -544,6 +544,7 @@ static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pc - static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) - { - snd_pcm_file_t *file = pcm->private_data; -+ snd_pcm_channel_area_t areas[pcm->channels]; - snd_pcm_sframes_t n; - - n = _snd_pcm_readi(file->gen.slave, buffer, size); -@@ -555,8 +556,10 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc - __snd_pcm_unlock(pcm); - if (n < 0) - return n; -- return n * 8 / pcm->frame_bits; -+ n = n * 8 / pcm->frame_bits; - } -+ snd_pcm_areas_from_buf(pcm, areas, buffer); -+ snd_pcm_file_add_frames(pcm, areas, 0, n); - return n; - } - -@@ -564,6 +567,7 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc - static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) - { - snd_pcm_file_t *file = pcm->private_data; -+ snd_pcm_channel_area_t areas[pcm->channels]; - snd_pcm_sframes_t n; - - if (file->ifd >= 0) { -@@ -572,6 +576,10 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm - } - - n = _snd_pcm_readn(file->gen.slave, bufs, size); -+ if (n > 0) { -+ snd_pcm_areas_from_bufs(pcm, areas, bufs); -+ snd_pcm_file_add_frames(pcm, areas, 0, n); -+ } - return n; - } - -@@ -635,7 +643,7 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - a->first = slave->sample_bits * channel; - a->step = slave->frame_bits; - } -- if ((file->fd < 0) && (pcm->stream == SND_PCM_STREAM_PLAYBACK)) { -+ if (file->fd < 0) { - err = snd_pcm_file_open_output_file(file); - if (err < 0) { - SYSERR("failed opening output file %s", file->fname); --- -2.9.3 - - -From a50496346f39e91ecd42cb09bc5c95321131be55 Mon Sep 17 00:00:00 2001 -From: Andreas Pape -Date: Fri, 17 Feb 2017 12:47:36 +0530 -Subject: [PATCH 29/37] pcm: status dump fix timestamp formatting - -nanosecond part formatted with %06 will give incorrect/confusing results: - -trigger_time: 154.9748287 -trigger_time: 154.60109090 -trigger_time: 154.110425257 - -time seems to run backwards... - -This patch converts to us before printing -which gives the correct/expected result: - -trigger_time: 154.009748 -trigger_time: 154.060109 -trigger_time: 154.110425 - -Signed-off-by: Andreas Pape -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c -index 493e903..a16fd86 100644 ---- a/src/pcm/pcm.c -+++ b/src/pcm/pcm.c -@@ -2194,9 +2194,10 @@ int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out) - assert(status); - snd_output_printf(out, " state : %s\n", snd_pcm_state_name((snd_pcm_state_t) status->state)); - snd_output_printf(out, " trigger_time: %ld.%06ld\n", -- status->trigger_tstamp.tv_sec, status->trigger_tstamp.tv_nsec); -+ status->trigger_tstamp.tv_sec, -+ status->trigger_tstamp.tv_nsec / 1000); - snd_output_printf(out, " tstamp : %ld.%06ld\n", -- status->tstamp.tv_sec, status->tstamp.tv_nsec); -+ status->tstamp.tv_sec, status->tstamp.tv_nsec / 1000); - snd_output_printf(out, " delay : %ld\n", (long)status->delay); - snd_output_printf(out, " avail : %ld\n", (long)status->avail); - snd_output_printf(out, " avail_max : %ld\n", (long)status->avail_max); --- -2.9.3 - - -From fbb957138135e09ed9fd0180dcad549aad815465 Mon Sep 17 00:00:00 2001 -From: Awais Belal -Date: Fri, 17 Feb 2017 12:47:49 +0530 -Subject: [PATCH 30/37] pcm: extplug: refinement of masks in extplug - -It should be possible to use empty mask format with extplug. -The refinement of mask via extplug is now modified, -to accept empty masks as well to work properly. - -Signed-off-by: Awais Belal -Signed-off-by: Mounesh Sutar -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_extplug.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c -index a04f826..1004f54 100644 ---- a/src/pcm/pcm_extplug.c -+++ b/src/pcm/pcm_extplug.c -@@ -172,6 +172,8 @@ int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int ty - unsigned int i; - - parm += type; -+ if (!parm->active) -+ return 0; - memset(&bits, 0, sizeof(bits)); - for (i = 0; i < parm->num_list; i++) - bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); --- -2.9.3 - - -From 97be19cf6f44fc5084828114c53281dff6e365b4 Mon Sep 17 00:00:00 2001 -From: Alan Young -Date: Thu, 7 Apr 2016 09:15:04 +0100 -Subject: [PATCH 31/37] pcm: rate: Add capability to pass configuration node to - plugins - -If a rate plugin uses a node (compound) instead of a plain string for -its "converter", and that compound is not a simple string array, then -the compound will be passed as an additional parameter to the new plugin -open() function (SND_PCM_RATE_PLUGIN_CONF_ENTRY(XXX)). The previous -open() function (SND_PCM_RATE_PLUGIN_ENTRY(XXX)) will be called if the -CONF version is not found. It is up to the plugin to determine whether -the presence of the conf parameter is mandatory. - -Signed-off-by: Alan Young -Signed-off-by: Takashi Iwai ---- - include/pcm_rate.h | 5 +++- - src/pcm/pcm_rate.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------ - 2 files changed, 82 insertions(+), 10 deletions(-) - -diff --git a/include/pcm_rate.h b/include/pcm_rate.h -index 4d70df2..da278ac 100644 ---- a/include/pcm_rate.h -+++ b/include/pcm_rate.h -@@ -120,11 +120,14 @@ typedef struct snd_pcm_rate_ops { - typedef int (*snd_pcm_rate_open_func_t)(unsigned int version, void **objp, - snd_pcm_rate_ops_t *opsp); - -+typedef int (*snd_pcm_rate_open_conf_func_t)(unsigned int version, void **objp, -+ snd_pcm_rate_ops_t *opsp, const snd_config_t *conf); -+ - /** - * Define the object entry for external PCM rate-converter plugins - */ - #define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open -- -+#define SND_PCM_RATE_PLUGIN_CONF_ENTRY(name) _snd_pcm_rate_##name##_open_conf - - #ifndef DOC_HIDDEN - /* old rate_ops for protocol version 0x010001 */ -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index cbb7618..46eb797 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -1258,26 +1258,48 @@ static const char *const default_rate_plugins[] = { - "speexrate", "linear", NULL - }; - --static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose) -+static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_config_t *converter_conf, int verbose) - { -- char open_name[64], lib_name[128], *lib = NULL; -+ char open_name[64], open_conf_name[64], lib_name[128], *lib = NULL; - snd_pcm_rate_open_func_t open_func; -+ snd_pcm_rate_open_conf_func_t open_conf_func; - int err; - - snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); -+ snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", type); - if (!is_builtin_plugin(type)) { - snprintf(lib_name, sizeof(lib_name), - "%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type); - lib = lib_name; - } -+ -+ rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; -+ rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; -+ rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; -+ -+ open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL); -+ if (open_conf_func) { -+ err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION, -+ &rate->obj, &rate->ops, converter_conf); -+ if (!err) { -+ rate->plugin_version = rate->ops.version; -+ if (rate->ops.get_supported_rates) -+ rate->ops.get_supported_rates(rate->obj, -+ &rate->rate_min, -+ &rate->rate_max); -+ rate->open_func = open_conf_func; -+ return 0; -+ } else { -+ snd_dlobj_cache_put(open_conf_func); -+ return err; -+ } -+ } -+ - open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose); - if (!open_func) - return -ENOENT; - - rate->open_func = open_func; -- rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; -- rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; -- rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; - - err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); - if (!err) { -@@ -1301,6 +1323,30 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose) - } - #endif - -+/* -+ * If the conf is an array of alternatives then the id of -+ * the first element will be "0" (or maybe NULL). Otherwise assume it is -+ * a structure. -+ */ -+static int is_string_array(const snd_config_t *conf) -+{ -+ snd_config_iterator_t i; -+ -+ if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) -+ return 0; -+ -+ i = snd_config_iterator_first(conf); -+ if (i && i != snd_config_iterator_end(conf)) { -+ snd_config_t *n = snd_config_iterator_entry(i); -+ const char *id; -+ snd_config_get_id(n, &id); -+ if (id && strcmp(id, "0") != 0) -+ return 0; -+ } -+ -+ return 1; -+} -+ - /** - * \brief Creates a new rate PCM - * \param pcmp Returns created PCM handle -@@ -1353,24 +1399,42 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - if (!converter) { - const char *const *types; - for (types = default_rate_plugins; *types; types++) { -- err = rate_open_func(rate, *types, 0); -+ err = rate_open_func(rate, *types, NULL, 0); - if (!err) { - type = *types; - break; - } - } - } else if (!snd_config_get_string(converter, &type)) -- err = rate_open_func(rate, type, 1); -- else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { -+ err = rate_open_func(rate, type, NULL, 1); -+ else if (is_string_array(converter)) { - snd_config_iterator_t i, next; - snd_config_for_each(i, next, converter) { - snd_config_t *n = snd_config_iterator_entry(i); - if (snd_config_get_string(n, &type) < 0) - break; -- err = rate_open_func(rate, type, 0); -+ err = rate_open_func(rate, type, NULL, 0); - if (!err) - break; - } -+ } else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { -+ snd_config_iterator_t i, next; -+ snd_config_for_each(i, next, converter) { -+ snd_config_t *n = snd_config_iterator_entry(i); -+ const char *id; -+ snd_config_get_id(n, &id); -+ if (strcmp(id, "name") != 0) -+ continue; -+ snd_config_get_string(n, &type); -+ break; -+ } -+ if (!type) { -+ SNDERR("No name given for rate converter"); -+ snd_pcm_free(pcm); -+ free(rate); -+ return -EINVAL; -+ } -+ err = rate_open_func(rate, type, converter, 1); - } else { - SNDERR("Invalid type for rate converter"); - snd_pcm_free(pcm); -@@ -1439,6 +1503,11 @@ pcm.name { - converter [ STR1 STR2 ... ] # optional - # Converter type, default is taken from - # defaults.pcm.rate_converter -+ # or -+ converter { # optional -+ name STR # Convertor type -+ xxx yyy # optional convertor-specific configuration -+ } - } - \endcode - --- -2.9.3 - - -From 3bad0a21b4d13d8d10691f382c836897fa7a7cb9 Mon Sep 17 00:00:00 2001 -From: Breno Leitao -Date: Wed, 22 Feb 2017 16:45:00 -0300 -Subject: [PATCH 32/37] Drop ppc64-specific workaround for versioned symbols - -Currently aserver fails to build when using parameter ---without-versioned, due to an workaround for ppc64 -(06221f86d207cb33ddd4867ca5301eeb247c4400). This workaround is -not required anymore on the ppc64 ABI v2, and, in fact is breaking the -compilation. Reverting this commit - -Signed-off-by: Breno Leitao -Signed-off-by: Takashi Iwai ---- - include/alsa-symbols.h | 17 ----------------- - 1 file changed, 17 deletions(-) - -diff --git a/include/alsa-symbols.h b/include/alsa-symbols.h -index 51cb982..eeacfdb 100644 ---- a/include/alsa-symbols.h -+++ b/include/alsa-symbols.h -@@ -29,19 +29,10 @@ - #define INTERNAL_CONCAT2_2(Pre, Post) Pre##Post - #define INTERNAL(Name) INTERNAL_CONCAT2_2(__, Name) - --#ifdef __powerpc64__ --# define symbol_version(real, name, version) \ -- __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version); \ -- __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@" #version) --# define default_symbol_version(real, name, version) \ -- __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version); \ -- __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@@" #version) --#else - # define symbol_version(real, name, version) \ - __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version) - # define default_symbol_version(real, name, version) \ - __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version) --#endif - - #ifdef USE_VERSIONED_SYMBOLS - #define use_symbol_version(real, name, version) \ -@@ -50,13 +41,6 @@ - default_symbol_version(real, name, version) - #else - #define use_symbol_version(real, name, version) /* nothing */ --#ifdef __powerpc64__ --#define use_default_symbol_version(real, name, version) \ -- __asm__ (".weak " ASM_NAME(#name)); \ -- __asm__ (".weak ." ASM_NAME(#name)); \ -- __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)); \ -- __asm__ (".set ." ASM_NAME(#name) ",." ASM_NAME(#real)) --#else - #if defined(__alpha__) || defined(__mips__) - #define use_default_symbol_version(real, name, version) \ - __asm__ (".weak " ASM_NAME(#name)); \ -@@ -67,6 +51,5 @@ - __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)) - #endif - #endif --#endif - - #endif /* __ALSA_SYMBOLS_H */ --- -2.9.3 - - -From b0e4652881f883023d2b190cf3897b7494d8d0ed Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 27 Feb 2017 09:25:24 +0100 -Subject: [PATCH 33/37] pcm_plugin: unify the snd_pcm_mmap_begin result value - checking - ---- - src/pcm/pcm_plugin.c | 26 +++++++++++++++++++------- - 1 file changed, 19 insertions(+), 7 deletions(-) - -diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c -index ad4a102..aaea2ab 100644 ---- a/src/pcm/pcm_plugin.c -+++ b/src/pcm/pcm_plugin.c -@@ -251,8 +251,12 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, - snd_pcm_uframes_t slave_offset; - snd_pcm_uframes_t slave_frames = ULONG_MAX; - -- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -- if (err < 0 || slave_frames == 0) -+ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -+ if (result < 0) { -+ err = result; -+ goto error; -+ } -+ if (slave_frames == 0) - break; - frames = plugin->write(pcm, areas, offset, frames, - slave_areas, slave_offset, &slave_frames); -@@ -304,7 +308,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, - snd_pcm_uframes_t slave_offset; - snd_pcm_uframes_t slave_frames = ULONG_MAX; - -- snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -+ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -+ if (result < 0) { -+ err = result; -+ goto error; -+ } - if (slave_frames == 0) - break; - frames = (plugin->read)(pcm, areas, offset, frames, -@@ -409,9 +417,11 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t slave_frames = ULONG_MAX; - snd_pcm_sframes_t result; - -- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -- if (err < 0) -+ 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->write(pcm, areas, appl_offset, frames, -@@ -481,9 +491,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) - snd_pcm_uframes_t slave_frames = ULONG_MAX; - snd_pcm_sframes_t result; - -- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); -- if (err < 0) -+ 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, --- -2.9.3 - - -From 8a38461fac67f6542308063ba8e9887a1a2fa84e Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 27 Feb 2017 09:26:33 +0100 -Subject: [PATCH 34/37] always handle return value from snd_config_get_id() - (coverity) - ---- - src/pcm/pcm_rate.c | 6 ++++-- - src/topology/data.c | 4 ++-- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 46eb797..f60b0ae 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -1339,7 +1339,8 @@ static int is_string_array(const snd_config_t *conf) - if (i && i != snd_config_iterator_end(conf)) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; -- snd_config_get_id(n, &id); -+ if (snd_config_get_id(n, &id) < 0) -+ return 0; - if (id && strcmp(id, "0") != 0) - return 0; - } -@@ -1422,7 +1423,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - snd_config_for_each(i, next, converter) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; -- snd_config_get_id(n, &id); -+ if (snd_config_get_id(n, &id) < 0) -+ continue; - if (strcmp(id, "name") != 0) - continue; - snd_config_get_string(n, &type); -diff --git a/src/topology/data.c b/src/topology/data.c -index e2aa38c..8fe2342 100644 ---- a/src/topology/data.c -+++ b/src/topology/data.c -@@ -653,8 +653,8 @@ static int parse_tuple_sets(snd_config_t *cfg, - int err; - - if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { -- snd_config_get_id(cfg, &id); -- SNDERR("error: compound type expected for %s", id); -+ if (snd_config_get_id(cfg, &id) >= 0) -+ SNDERR("error: compound type expected for %s", id); - return -EINVAL; - } - --- -2.9.3 - - -From b96f6f47852aa145645fb8626d009ec532246e55 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 27 Feb 2017 09:29:18 +0100 -Subject: [PATCH 35/37] pcm file plugin: handle snd_pcm_mmap_begin() error path - in snd_pcm_file_mmap_commit() - ---- - src/pcm/pcm_file.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c -index 0363f84..8012251 100644 ---- a/src/pcm/pcm_file.c -+++ b/src/pcm/pcm_file.c -@@ -593,11 +593,13 @@ static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, - const snd_pcm_channel_area_t *areas; - snd_pcm_sframes_t result; - -- snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); -- assert(ofs == offset && siz == size); -- result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); -- if (result > 0) -- snd_pcm_file_add_frames(pcm, areas, ofs, result); -+ result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); -+ if (result >= 0) { -+ assert(ofs == offset && siz == size); -+ result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); -+ if (result > 0) -+ snd_pcm_file_add_frames(pcm, areas, ofs, result); -+ } - return result; - } - --- -2.9.3 - - -From db0e1dcfc22fb2e408a12993cda2d604e0fb10f8 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 27 Feb 2017 09:46:18 +0100 -Subject: [PATCH 36/37] topology: coverity - remove dead code - ---- - src/topology/ctl.c | 5 ++--- - src/topology/data.c | 2 +- - src/topology/pcm.c | 17 +++++++---------- - 3 files changed, 10 insertions(+), 14 deletions(-) - -diff --git a/src/topology/ctl.c b/src/topology/ctl.c -index 1da3d18..c026c2a 100644 ---- a/src/topology/ctl.c -+++ b/src/topology/ctl.c -@@ -173,7 +173,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, - { - struct tplg_ref *ref; - struct list_head *base, *pos; -- int err = 0; -+ int err; - - base = &elem->ref_list; - -@@ -198,8 +198,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, - SNDERR("error: cannot find '%s' referenced by" - " control '%s'\n", ref->id, elem->id); - return -EINVAL; -- } else if (err < 0) -- return err; -+ } - } - - return 0; -diff --git a/src/topology/data.c b/src/topology/data.c -index 8fe2342..31e4ee1 100644 ---- a/src/topology/data.c -+++ b/src/topology/data.c -@@ -917,7 +917,7 @@ int tplg_build_manifest_data(snd_tplg_t *tplg) - list_for_each(pos, base) { - - ref = list_entry(pos, struct tplg_ref, list); -- if (ref->id == NULL || ref->elem) -+ if (ref->elem) - continue; - - if (ref->type == SND_TPLG_TYPE_DATA) { -diff --git a/src/topology/pcm.c b/src/topology/pcm.c -index 5568d57..50a373a 100644 ---- a/src/topology/pcm.c -+++ b/src/topology/pcm.c -@@ -79,8 +79,8 @@ static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) - int err; - - err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps); -- if (err < 0) -- return err; -+ if (err < 0) -+ return err; - - /* merge private data from the referenced data elements */ - base = &elem->ref_list; -@@ -96,8 +96,7 @@ static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) - SNDERR("error: cannot find '%s' referenced by" - " PCM '%s'\n", ref->id, elem->id); - return -EINVAL; -- } else if (err < 0) -- return err; -+ } - } - - return 0; -@@ -1208,12 +1207,10 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) - - /* ID and names */ - link->id = link_tpl->id; -- if (link->name) -- elem_copy_text(link->name, link_tpl->name, -- SNDRV_CTL_ELEM_ID_NAME_MAXLEN); -- if (link->stream_name) -- elem_copy_text(link->stream_name, link_tpl->stream_name, -- SNDRV_CTL_ELEM_ID_NAME_MAXLEN); -+ elem_copy_text(link->name, link_tpl->name, -+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); -+ elem_copy_text(link->stream_name, link_tpl->stream_name, -+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); - - /* stream configs */ - if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) --- -2.9.3 - - -From ad188bbf7813eab6f42dcdf617aa947107118857 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 27 Feb 2017 09:53:26 +0100 -Subject: [PATCH 37/37] ucm parser: fix possible string overflow in - uc_mgr_import_master_config() - ---- - src/ucm/parser.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/ucm/parser.c b/src/ucm/parser.c -index 798bf48..b79b92d 100644 ---- a/src/ucm/parser.c -+++ b/src/ucm/parser.c -@@ -1453,7 +1453,8 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) - err = load_master_config(uc_mgr->card_name, &cfg); - if (err < 0) - return err; -- strcpy(uc_mgr->conf_file_name, uc_mgr->card_name); -+ strncpy(uc_mgr->conf_file_name, uc_mgr->card_name, MAX_CARD_LONG_NAME); -+ uc_mgr->conf_file_name[MAX_CARD_LONG_NAME-1] = '\0'; - } - - err = parse_master_file(uc_mgr, cfg); --- -2.9.3 - diff --git a/SOURCES/alsa-lib-1.1.4.1-post.patch b/SOURCES/alsa-lib-1.1.4.1-post.patch new file mode 100644 index 0000000..3d26a42 --- /dev/null +++ b/SOURCES/alsa-lib-1.1.4.1-post.patch @@ -0,0 +1,4493 @@ +From 6d843ba5d377961f6765466ba0cc362dd10f7557 Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Wed, 14 Jun 2017 12:37:39 +0100 +Subject: [PATCH 01/39] topology: Add support for missing fields parser. + +The alsa-lib topology parser is missing some fields for certain objects that +are part of the ABI. This patch adds the missing fields to the parser. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/pcm.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 183 insertions(+) + +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index daef20e4..0f4deb4f 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -383,6 +383,49 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, + tplg_dbg("\t\t%s: %d\n", id, sc->channels_max); + continue; + } ++ ++ if (strcmp(id, "periods_min") == 0) { ++ sc->periods_min = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->periods_min); ++ continue; ++ } ++ ++ if (strcmp(id, "periods_max") == 0) { ++ sc->periods_max = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->periods_max); ++ continue; ++ } ++ ++ if (strcmp(id, "period_size_min") == 0) { ++ sc->period_size_min = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->period_size_min); ++ continue; ++ } ++ ++ if (strcmp(id, "period_size_max") == 0) { ++ sc->period_size_max = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->period_size_max); ++ continue; ++ } ++ ++ if (strcmp(id, "buffer_size_min") == 0) { ++ sc->buffer_size_min = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_min); ++ continue; ++ } ++ ++ if (strcmp(id, "buffer_size_max") == 0) { ++ sc->buffer_size_max = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->buffer_size_max); ++ continue; ++ } ++ ++ if (strcmp(id, "sig_bits") == 0) { ++ sc->sig_bits = atoi(val); ++ tplg_dbg("\t\t%s: %d\n", id, sc->sig_bits); ++ continue; ++ } ++ + } + + return 0; +@@ -572,6 +615,17 @@ int tplg_parse_pcm(snd_tplg_t *tplg, + continue; + } + ++ if (strcmp(id, "compress") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ if (strcmp(val, "true") == 0) ++ pcm->compress = 1; ++ ++ tplg_dbg("\t%s: %s\n", id, val); ++ continue; ++ } ++ + if (strcmp(id, "dai") == 0) { + err = tplg_parse_compound(tplg, n, + tplg_parse_fe_dai, elem); +@@ -655,6 +709,26 @@ int tplg_parse_dai(snd_tplg_t *tplg, + continue; + } + ++ if (strcmp(id, "playback") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ dai->playback = atoi(val); ++ tplg_dbg("\t%s: %d\n", id, dai->playback); ++ continue; ++ } ++ ++ ++ if (strcmp(id, "capture") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ dai->capture = atoi(val); ++ tplg_dbg("\t%s: %d\n", id, dai->capture); ++ continue; ++ } ++ ++ + /* stream capabilities */ + if (strcmp(id, "pcm") == 0) { + err = tplg_parse_compound(tplg, n, +@@ -997,6 +1071,23 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + continue; + } + ++ if (strcmp(id, "bclk_freq") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->bclk_rate = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "bclk_invert") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ if (!strcmp(val, "true")) ++ hw_cfg->invert_bclk = true; ++ continue; ++ } ++ + if (strcmp(id, "fsync") == 0) { + if (snd_config_get_string(n, &val) < 0) + return -EINVAL; +@@ -1005,6 +1096,98 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + hw_cfg->fsync_master = true; + continue; + } ++ ++ if (strcmp(id, "fsync_invert") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ if (!strcmp(val, "true")) ++ hw_cfg->invert_fsync = true; ++ continue; ++ } ++ ++ if (strcmp(id, "fsync_freq") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->fsync_rate = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "mclk_freq") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->mclk_rate = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "mclk") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ if (!strcmp(val, "master")) ++ hw_cfg->mclk_direction = true; ++ continue; ++ } ++ ++ if (strcmp(id, "pm_gate_clocks") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ if (!strcmp(val, "true")) ++ hw_cfg->clock_gated = true; ++ continue; ++ } ++ ++ if (strcmp(id, "tdm_slots") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->tdm_slots = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "tdm_slot_width") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->tdm_slot_width = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "tx_slots") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->tx_slots = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "rx_slots") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->rx_slots = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "tx_channels") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->tx_channels = atoi(val); ++ continue; ++ } ++ ++ if (strcmp(id, "rx_channels") == 0) { ++ if (snd_config_get_string(n, &val) < 0) ++ return -EINVAL; ++ ++ hw_cfg->rx_channels = atoi(val); ++ continue; ++ } ++ + } + + return 0; +-- +2.13.5 + + +From 89c96ad7fb0168411260196560892835d0adeddf Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Wed, 14 Jun 2017 12:37:40 +0100 +Subject: [PATCH 02/39] topology: disable alsa-lib topology debug output by + default. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/tplg_local.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h +index 42e3201d..60af0177 100644 +--- a/src/topology/tplg_local.h ++++ b/src/topology/tplg_local.h +@@ -22,7 +22,6 @@ + #include + #include + +-#define TPLG_DEBUG + #ifdef TPLG_DEBUG + #define tplg_dbg SNDERR + #else +-- +2.13.5 + + +From c550a421a3ff5b11ccd4a506ae04fdc6c5347ae3 Mon Sep 17 00:00:00 2001 +From: Guneshwor Singh +Date: Tue, 20 Jun 2017 09:45:45 +0530 +Subject: [PATCH 03/39] topology: Add parsing for rates from conf + +In alsa-lib topology parser, rate_min and rate_max are parsed currently. +Add support to parse rates also. + +Signed-off-by: Guneshwor Singh +Signed-off-by: Takashi Iwai +--- + include/topology.h | 1 + + src/topology/pcm.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ + src/topology/tplg_local.h | 20 +++++++++++++ + 3 files changed, 92 insertions(+) + +diff --git a/include/topology.h b/include/topology.h +index ccb3a004..42d23762 100644 +--- a/include/topology.h ++++ b/include/topology.h +@@ -534,6 +534,7 @@ extern "C" { + * SectionPCMCapabilities."name" { + * + * formats "S24_LE,S16_LE" # Supported formats ++ * rates "48000" # Supported rates + * rate_min "48000" # Max supported sample rate + * rate_max "48000" # Min supported sample rate + * channels_min "2" # Min number of channels +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 0f4deb4f..bb63142e 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -20,6 +20,26 @@ + #include "list.h" + #include "tplg_local.h" + ++#define RATE(v) [SND_PCM_RATE_##v] = #v ++ ++static const char *const snd_pcm_rate_names[] = { ++ RATE(5512), ++ RATE(8000), ++ RATE(11025), ++ RATE(16000), ++ RATE(22050), ++ RATE(32000), ++ RATE(44100), ++ RATE(48000), ++ RATE(64000), ++ RATE(88200), ++ RATE(96000), ++ RATE(176400), ++ RATE(192000), ++ RATE(CONTINUOUS), ++ RATE(KNOT), ++}; ++ + struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id) + { + struct list_head *pos; +@@ -309,6 +329,42 @@ static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str) + return 0; + } + ++static int get_rate_value(const char* name) ++{ ++ int rate; ++ for (rate = 0; rate <= SND_PCM_RATE_LAST; rate++) { ++ if (snd_pcm_rate_names[rate] && ++ strcasecmp(name, snd_pcm_rate_names[rate]) == 0) { ++ return rate; ++ } ++ } ++ ++ return SND_PCM_RATE_UNKNOWN; ++} ++ ++static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str) ++{ ++ char *s = NULL; ++ snd_pcm_rates_t rate; ++ int i = 0; ++ ++ s = strtok(str, ","); ++ while (s) { ++ rate = get_rate_value(s); ++ ++ if (rate == SND_PCM_RATE_UNKNOWN) { ++ SNDERR("error: unsupported stream rate %s\n", s); ++ return -EINVAL; ++ } ++ ++ caps->rates |= 1 << rate; ++ s = strtok(NULL, ", "); ++ i++; ++ } ++ ++ return 0; ++} ++ + /* Parse pcm stream capabilities */ + int tplg_parse_stream_caps(snd_tplg_t *tplg, + snd_config_t *cfg, void *private ATTRIBUTE_UNUSED) +@@ -360,6 +416,21 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, + continue; + } + ++ if (strcmp(id, "rates") == 0) { ++ s = strdup(val); ++ if (!s) ++ return -ENOMEM; ++ ++ err = split_rate(sc, s); ++ free(s); ++ ++ if (err < 0) ++ return err; ++ ++ tplg_dbg("\t\t%s: %s\n", id, val); ++ continue; ++ } ++ + if (strcmp(id, "rate_min") == 0) { + sc->rate_min = atoi(val); + tplg_dbg("\t\t%s: %d\n", id, sc->rate_min); +diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h +index 60af0177..af599145 100644 +--- a/src/topology/tplg_local.h ++++ b/src/topology/tplg_local.h +@@ -37,6 +37,26 @@ + struct tplg_ref; + struct tplg_elem; + ++typedef enum _snd_pcm_rates { ++ SND_PCM_RATE_UNKNOWN = -1, ++ SND_PCM_RATE_5512 = 0, ++ SND_PCM_RATE_8000, ++ SND_PCM_RATE_11025, ++ SND_PCM_RATE_16000, ++ SND_PCM_RATE_22050, ++ SND_PCM_RATE_32000, ++ SND_PCM_RATE_44100, ++ SND_PCM_RATE_48000, ++ SND_PCM_RATE_64000, ++ SND_PCM_RATE_88200, ++ SND_PCM_RATE_96000, ++ SND_PCM_RATE_176400, ++ SND_PCM_RATE_192000, ++ SND_PCM_RATE_CONTINUOUS = 30, ++ SND_PCM_RATE_KNOT = 31, ++ SND_PCM_RATE_LAST = SND_PCM_RATE_KNOT, ++} snd_pcm_rates_t; ++ + struct snd_tplg { + + /* opaque vendor data */ +-- +2.13.5 + + +From 6c535573008e474c471c100c5bfa5383308020f3 Mon Sep 17 00:00:00 2001 +From: Alexander Tsoy +Date: Sun, 18 Jun 2017 23:23:02 +0300 +Subject: [PATCH 04/39] conf: USB-Audio: fix dsnoop args for Audiophile USB + card + +Fixes: a9b129955659 ("USB-Audio.conf: fix definition for M-Audio AudioP...") +Signed-off-by: Alexander Tsoy +Signed-off-by: Takashi Iwai +--- + src/conf/cards/USB-Audio.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index e365f297..f72ef121 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -90,7 +90,7 @@ USB-Audio."Audiophile USB (tm)".pcm.default { + type plug + slave.pcm { + @func concat +- strings [ "dsnoop:DEVICE=1,CARD=" $CARD ] ++ strings [ "dsnoop:DEV=1,CARD=" $CARD ] + } + } + } +-- +2.13.5 + + +From c09e3b2d5b7fe893b99df3c87577936a3f386d99 Mon Sep 17 00:00:00 2001 +From: Alexander Tsoy +Date: Sun, 18 Jun 2017 23:23:03 +0300 +Subject: [PATCH 05/39] conf: USB-Audio: allow custom definitions for "default" + devices + +Fixes: a9b129955659 ("USB-Audio.conf: fix definition for M-Audio AudioP...") +Signed-off-by: Alexander Tsoy +Signed-off-by: Takashi Iwai +--- + src/conf/cards/USB-Audio.conf | 77 ++++++++++++++++++++++++------------------- + 1 file changed, 44 insertions(+), 33 deletions(-) + +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index f72ef121..cc8c718c 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -67,7 +67,7 @@ USB-Audio.pcm.iec958_2_device { + } + + +-# If a device requires non-standard definitions for front, surround40, ++# If a device requires non-standard definitions for front, default, surround40, + # surround51, surround71 or iec958, they can be defined here. + + # M-Audio AudioPhile USB: +@@ -125,13 +125,13 @@ USB-Audio."Audio Advantage MicroII".pcm.iec958 { + @args.AES2 { type integer } + @args.AES3 { type integer } + +- type hooks +- slave.pcm { ++ type hooks ++ slave.pcm { + type hw + card $CARD +- } ++ } + +- hooks.0 { ++ hooks.0 { + type ctl_elems + hook_args [ + { +@@ -174,41 +174,52 @@ USB-Audio.pcm.front.0 { + card $CARD + device 0 + } +-} ++} + + USB-Audio.pcm.default { + @args [ CARD ] + @args.CARD { type string } +- type asym +- playback.pcm { +- type plug +- slave.pcm { +- @func refer +- name { +- @func concat +- strings [ +- "cards.USB-Audio.pcm.default_playback_dmix_" +- { +- @func refer +- name { +- @func concat +- strings [ +- "cards.USB-Audio.pcm.use_dmix." +- { @func card_name card $CARD } +- ] ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards.USB-Audio." ++ { @func card_name card $CARD } ++ ".pcm.default:CARD=" $CARD ++ ] ++ } ++ default { ++ type asym ++ playback.pcm { ++ type plug ++ slave.pcm { ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards.USB-Audio.pcm.default_playback_dmix_" ++ { ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards.USB-Audio.pcm.use_dmix." ++ { @func card_name card $CARD } ++ ] ++ } ++ default yes + } +- default yes +- } +- ":CARD=" $CARD +- ] ++ ":CARD=" $CARD ++ ] ++ } + } + } +- } +- capture.pcm { +- type plug +- slave.pcm { +- @func concat +- strings [ "dsnoop:" $CARD ] ++ capture.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dsnoop:" $CARD ] ++ } + } + } + } +-- +2.13.5 + + +From f10bc243e42142c568d90f540e806aefb45d8bac Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 23 Jun 2017 22:09:23 +0900 +Subject: [PATCH 06/39] pcm: obsolete 'mmap_emulation' parameter of + snd_pcm_hw_open_fd() + +A function, snd_pcm_hw_open_fd(), is just for internal use. This function +has an obsoleted parameter and we can remove it without any compatibility +issue. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 2 +- + src/pcm/pcm_hw.c | 6 ++---- + src/pcm/pcm_local.h | 3 ++- + 3 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 43702601..9fd376d8 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -1523,7 +1523,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm + int ret; + snd_pcm_t *spcm; + +- ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0, 0); ++ ret = snd_pcm_hw_open_fd(spcmp, client_name, dmix->hw_fd, 0); + if (ret < 0) { + SNDERR("unable to open hardware"); + return ret; +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 30cd5d0f..f0efcde3 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -1410,15 +1410,13 @@ static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = { + * \param pcmp Returns created PCM handle + * \param name Name of PCM + * \param fd File descriptor +- * \param mmap_emulation Obsoleted parameter + * \param sync_ptr_ioctl Boolean flag for sync_ptr ioctl + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely + * changed in future. + */ +-int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, +- int fd, int mmap_emulation ATTRIBUTE_UNUSED, ++int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + int sync_ptr_ioctl) + { + int ver, mode; +@@ -1615,7 +1613,7 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, + } + } + snd_ctl_close(ctl); +- return snd_pcm_hw_open_fd(pcmp, name, fd, 0, sync_ptr_ioctl); ++ return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl); + _err: + snd_ctl_close(ctl); + return ret; +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index e4f65218..7600daa3 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -935,7 +935,8 @@ snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, + + #define snd_pcm_conf_generic_id(id) _snd_conf_generic_id(id) + +-int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl); ++int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, ++ int sync_ptr_ioctl); + int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_t *slave, int close_slave); + +-- +2.13.5 + + +From 8beab3eb8a4346f823cb42c507122f0abbf9025f Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 23 Jun 2017 22:09:24 +0900 +Subject: [PATCH 07/39] pcm: minor code cleanup for ioctl call + +When error occurs, return value from ioctl(2) is -1 and error code can +be got thread local variable, errno. It's OK just to check the return +value without any assignment. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index f0efcde3..de6fd1af 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -132,8 +132,7 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) + { + int err; + hw->sync_ptr->flags = flags; +- err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR, (hw)->sync_ptr); +- if (err < 0) { ++ if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); + return err; +-- +2.13.5 + + +From 987788dbfe65ae7811868654ba11c05b4582955f Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 20 Jun 2017 12:39:23 +0200 +Subject: [PATCH 08/39] pcm: hw: Remove superfluous call of + snd_pcm_set_appl_ptr() + +There is a call of snd_pcm_set_appl_ptr() in snd_pcm_hw_hw_params() +only for the capture direction. This must be a leftover from the +ancient code. Although it's harmless for now, it's superfluous and +confusing. Let's kill it. + +Reviewed-by: Takashi Sakamoto +Tested-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index de6fd1af..a648d12c 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -329,14 +329,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + params->info &= ~0xf0000000; + if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) + params->info |= SND_PCM_INFO_MONOTONIC; +- err = sync_ptr(hw, 0); +- if (err < 0) +- return err; +- if (pcm->stream == SND_PCM_STREAM_CAPTURE) { +- snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, +- SNDRV_PCM_MMAP_OFFSET_CONTROL); +- } +- return 0; ++ return sync_ptr(hw, 0); + } + + static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) +-- +2.13.5 + + +From 2fbad9bc4ead7ea0c19529c4496080af9b8ab275 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:19 +0900 +Subject: [PATCH 09/39] pcm: hw: add helper functions to map/unmap + status/control data for runtime of PCM substream + +Handling mapping operation for status/control data includes some +supplemental operations for fallback mode. It's better to have helper +functions for this purpose. + +This commit adds the helper functions. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 48 ++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 34 insertions(+), 14 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index a648d12c..abf4afe0 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -866,7 +867,7 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u + return xfern.result; + } + +-static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) ++static int map_status_data(snd_pcm_t *pcm) + { + snd_pcm_hw_t *hw = pcm->private_data; + struct snd_pcm_sync_ptr sync_ptr; +@@ -900,7 +901,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm) + return 0; + } + +-static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) ++static int map_control_data(snd_pcm_t *pcm) + { + snd_pcm_hw_t *hw = pcm->private_data; + void *ptr; +@@ -922,10 +923,28 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm) + return 0; + } + +-static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) ++static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + { + snd_pcm_hw_t *hw = pcm->private_data; + int err; ++ ++ hw->sync_ptr_ioctl = (int)force_fallback; ++ ++ err = map_status_data(pcm); ++ if (err < 0) ++ return err; ++ ++ err = map_control_data(pcm); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int unmap_status_data(snd_pcm_hw_t *hw) ++{ ++ int err; ++ + if (hw->sync_ptr_ioctl) { + free(hw->sync_ptr); + hw->sync_ptr = NULL; +@@ -939,10 +958,10 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm) + return 0; + } + +-static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) ++static int unmap_control_data(snd_pcm_hw_t *hw) + { +- snd_pcm_hw_t *hw = pcm->private_data; + int err; ++ + if (hw->sync_ptr_ioctl) { + free(hw->sync_ptr); + hw->sync_ptr = NULL; +@@ -956,6 +975,12 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) + return 0; + } + ++static void unmap_status_and_control_data(snd_pcm_hw_t *hw) ++{ ++ unmap_status_data(hw); ++ unmap_control_data(hw); ++} ++ + static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) + { + return 0; +@@ -974,8 +999,9 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) + err = -errno; + SYSMSG("close failed (%i)\n", err); + } +- snd_pcm_hw_munmap_status(pcm); +- snd_pcm_hw_munmap_control(pcm); ++ ++ unmap_status_and_control_data(hw); ++ + free(hw); + return err; + } +@@ -1484,7 +1510,6 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + hw->device = info.device; + hw->subdevice = info.subdevice; + hw->fd = fd; +- hw->sync_ptr_ioctl = sync_ptr_ioctl; + /* no restriction */ + hw->format = SND_PCM_FORMAT_UNKNOWN; + hw->rate = 0; +@@ -1508,12 +1533,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + #endif + pcm->own_state_check = 1; /* skip the common state check */ + +- ret = snd_pcm_hw_mmap_status(pcm); +- if (ret < 0) { +- snd_pcm_close(pcm); +- return ret; +- } +- ret = snd_pcm_hw_mmap_control(pcm); ++ ret = map_status_and_control_data(pcm, !!sync_ptr_ioctl); + if (ret < 0) { + snd_pcm_close(pcm); + return ret; +-- +2.13.5 + + +From 812654881a370691fba3ecbd4c175c74c32b9eae Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:20 +0900 +Subject: [PATCH 10/39] pcm: hw: add an arrangement for initialization of + appl_ptr/avail_min + +Regardless of success/failure mapping of control/status data for runtime of +PCM substream, appl_ptr/avail_min parameters are initialized. In current +implementation, they are initialized in case-dependent, different places. +It's possible to collect them to one place. + +This commit unifies relevant code in a place after all of trials for the +mappings are finished. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 42 ++++++++++++++++++++++-------------------- + 1 file changed, 22 insertions(+), 20 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index abf4afe0..c60a521b 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -867,10 +867,8 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u + return xfern.result; + } + +-static int map_status_data(snd_pcm_t *pcm) ++static int map_status_data(snd_pcm_hw_t *hw) + { +- snd_pcm_hw_t *hw = pcm->private_data; +- struct snd_pcm_sync_ptr sync_ptr; + void *ptr; + int err; + ptr = MAP_FAILED; +@@ -879,15 +877,6 @@ static int map_status_data(snd_pcm_t *pcm) + PROT_READ, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + if (ptr == MAP_FAILED || ptr == NULL) { +- memset(&sync_ptr, 0, sizeof(sync_ptr)); +- sync_ptr.c.control.appl_ptr = 0; +- sync_ptr.c.control.avail_min = 1; +- err = ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, &sync_ptr); +- if (err < 0) { +- err = -errno; +- SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); +- return err; +- } + hw->sync_ptr = calloc(1, sizeof(struct snd_pcm_sync_ptr)); + if (hw->sync_ptr == NULL) + return -ENOMEM; +@@ -897,13 +886,12 @@ static int map_status_data(snd_pcm_t *pcm) + } else { + hw->mmap_status = ptr; + } +- snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct snd_pcm_mmap_status, hw_ptr)); ++ + return 0; + } + +-static int map_control_data(snd_pcm_t *pcm) ++static int map_control_data(snd_pcm_hw_t *hw) + { +- snd_pcm_hw_t *hw = pcm->private_data; + void *ptr; + int err; + if (hw->sync_ptr == NULL) { +@@ -916,10 +904,8 @@ static int map_control_data(snd_pcm_t *pcm) + return err; + } + hw->mmap_control = ptr; +- } else { +- hw->mmap_control->avail_min = 1; + } +- snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); ++ + return 0; + } + +@@ -930,14 +916,30 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + + hw->sync_ptr_ioctl = (int)force_fallback; + +- err = map_status_data(pcm); ++ err = map_status_data(hw); + if (err < 0) + return err; + +- err = map_control_data(pcm); ++ err = map_control_data(hw); + if (err < 0) + return err; + ++ /* Initialize the data. */ ++ hw->mmap_control->appl_ptr = 0; ++ hw->mmap_control->avail_min = 1; ++ snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, ++ SNDRV_PCM_MMAP_OFFSET_STATUS + ++ offsetof(struct snd_pcm_mmap_status, hw_ptr)); ++ snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, ++ SNDRV_PCM_MMAP_OFFSET_CONTROL); ++ if (hw->sync_ptr_ioctl) { ++ if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { ++ err = -errno; ++ SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); ++ return err; ++ } ++ } ++ + return 0; + } + +-- +2.13.5 + + +From cb7503eba15714c40630d9e26bf7e5905ee3da50 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:21 +0900 +Subject: [PATCH 11/39] pcm: hw: deallocate fallback buffer when trials of + unmapping finished + +In current implementation, deallocation of fallback buffer is done at +several places. + +This commit unifies these deallocations in one place. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 43 +++++++++++++++++-------------------------- + 1 file changed, 17 insertions(+), 26 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index c60a521b..1d34956c 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -943,44 +943,35 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + return 0; + } + +-static int unmap_status_data(snd_pcm_hw_t *hw) ++static void unmap_status_data(snd_pcm_hw_t *hw) + { +- int err; +- +- if (hw->sync_ptr_ioctl) { +- free(hw->sync_ptr); +- hw->sync_ptr = NULL; +- } else { +- if (munmap((void*)hw->mmap_status, page_align(sizeof(*hw->mmap_status))) < 0) { +- err = -errno; +- SYSMSG("status munmap failed (%i)", err); +- return err; +- } ++ if (!hw->sync_ptr) { ++ if (munmap((void *)hw->mmap_status, ++ page_align(sizeof(*hw->mmap_status))) < 0) ++ SYSMSG("status munmap failed (%u)", errno); + } +- return 0; + } + +-static int unmap_control_data(snd_pcm_hw_t *hw) ++static void unmap_control_data(snd_pcm_hw_t *hw) + { +- int err; +- +- if (hw->sync_ptr_ioctl) { +- free(hw->sync_ptr); +- hw->sync_ptr = NULL; +- } else { +- if (munmap(hw->mmap_control, page_align(sizeof(*hw->mmap_control))) < 0) { +- err = -errno; +- SYSMSG("control munmap failed (%i)", err); +- return err; +- } ++ if (!hw->sync_ptr) { ++ if (munmap((void *)hw->mmap_control, ++ page_align(sizeof(*hw->mmap_control))) < 0) ++ SYSMSG("control munmap failed (%u)", errno); + } +- return 0; + } + + static void unmap_status_and_control_data(snd_pcm_hw_t *hw) + { + unmap_status_data(hw); + unmap_control_data(hw); ++ ++ if (hw->sync_ptr) ++ free(hw->sync_ptr); ++ ++ hw->mmap_status = NULL; ++ hw->mmap_control = NULL; ++ hw->sync_ptr = NULL; + } + + static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +-- +2.13.5 + + +From afadf61e44706880c32a854648645409c82dc0a2 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:22 +0900 +Subject: [PATCH 12/39] pcm: hw: allocate fallback buffer in advance of trials + of mapping + +When allowing failure of map operation for both of status/control data +for runtime of PCM substream, applications need to use fallback buffer +for an alternative ioctl. However, in current implementation, status +mapping is dominant to the allocation. + +This commit moves code for the allocation outside of the mapping +operation for status data. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 1d34956c..a3d1f137 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -867,21 +867,18 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u + return xfern.result; + } + +-static int map_status_data(snd_pcm_hw_t *hw) ++static int map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr) + { + void *ptr; +- int err; ++ + ptr = MAP_FAILED; + if (hw->sync_ptr_ioctl == 0) + ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_status)), + PROT_READ, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + if (ptr == MAP_FAILED || ptr == NULL) { +- hw->sync_ptr = calloc(1, sizeof(struct snd_pcm_sync_ptr)); +- if (hw->sync_ptr == NULL) +- return -ENOMEM; +- hw->mmap_status = &hw->sync_ptr->s.status; +- hw->mmap_control = &hw->sync_ptr->c.control; ++ hw->mmap_status = &sync_ptr->s.status; ++ hw->mmap_control = &sync_ptr->c.control; + hw->sync_ptr_ioctl = 1; + } else { + hw->mmap_status = ptr; +@@ -894,7 +891,7 @@ static int map_control_data(snd_pcm_hw_t *hw) + { + void *ptr; + int err; +- if (hw->sync_ptr == NULL) { ++ if (hw->sync_ptr_ioctl == 0) { + ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); +@@ -912,11 +909,18 @@ static int map_control_data(snd_pcm_hw_t *hw) + static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + { + snd_pcm_hw_t *hw = pcm->private_data; ++ struct snd_pcm_sync_ptr *sync_ptr; + int err; + ++ /* Preparation for fallback to failure of mmap(2). */ ++ sync_ptr = malloc(sizeof(*sync_ptr)); ++ if (sync_ptr == NULL) ++ return -ENOMEM; ++ memset(sync_ptr, 0, sizeof(*sync_ptr)); ++ + hw->sync_ptr_ioctl = (int)force_fallback; + +- err = map_status_data(hw); ++ err = map_status_data(hw, sync_ptr); + if (err < 0) + return err; + +@@ -924,6 +928,14 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + if (err < 0) + return err; + ++ /* Any fallback mode needs to keep the buffer. */ ++ if (hw->sync_ptr_ioctl == 0) { ++ hw->sync_ptr = sync_ptr; ++ } else { ++ free(sync_ptr); ++ hw->sync_ptr = NULL; ++ } ++ + /* Initialize the data. */ + hw->mmap_control->appl_ptr = 0; + hw->mmap_control->avail_min = 1; +-- +2.13.5 + + +From 9c9e3d0822777b36d7c8cae21550b180d108a160 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:23 +0900 +Subject: [PATCH 13/39] pcm: hw: maintain fallback mode for status data mapping + +In current implementation, results to map status/control data are not +maintained separately. It's handled as a fatal error that mapping of status +data is successful and mapping of control data is failed. However, it's +possible to handle this case by utilizing fallback buffer. + +This commit adds a member into a local structure to maintain fallback mode +just for the mapping of status data as a preparation of later commit, in +which mapping results are maintained separately for each of status/control +data. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 78 ++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 44 insertions(+), 34 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index a3d1f137..78857941 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -91,10 +91,12 @@ typedef struct { + int version; + int fd; + int card, device, subdevice; +- int sync_ptr_ioctl; ++ + volatile struct snd_pcm_mmap_status * mmap_status; + struct snd_pcm_mmap_control *mmap_control; ++ bool mmap_status_fallbacked; + struct snd_pcm_sync_ptr *sync_ptr; ++ + int period_event; + snd_timer_t *period_timer; + struct pollfd period_timer_pfd; +@@ -867,42 +869,53 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u + return xfern.result; + } + +-static int map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr) ++static bool map_status_data(snd_pcm_hw_t *hw, struct snd_pcm_sync_ptr *sync_ptr, ++ bool force_fallback) + { +- void *ptr; ++ struct snd_pcm_mmap_status *mmap_status; ++ bool fallbacked; ++ ++ mmap_status = MAP_FAILED; ++ if (!force_fallback) { ++ mmap_status = mmap(NULL, page_align(sizeof(*mmap_status)), ++ PROT_READ, MAP_FILE|MAP_SHARED, ++ hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); ++ } + +- ptr = MAP_FAILED; +- if (hw->sync_ptr_ioctl == 0) +- ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_status)), +- PROT_READ, MAP_FILE|MAP_SHARED, +- hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); +- if (ptr == MAP_FAILED || ptr == NULL) { +- hw->mmap_status = &sync_ptr->s.status; +- hw->mmap_control = &sync_ptr->c.control; +- hw->sync_ptr_ioctl = 1; ++ if (mmap_status == MAP_FAILED || mmap_status == NULL) { ++ mmap_status = &sync_ptr->s.status; ++ fallbacked = true; + } else { +- hw->mmap_status = ptr; ++ fallbacked = false; + } + +- return 0; ++ hw->mmap_status = mmap_status; ++ ++ return fallbacked; + } + +-static int map_control_data(snd_pcm_hw_t *hw) ++static bool map_control_data(snd_pcm_hw_t *hw, ++ struct snd_pcm_sync_ptr *sync_ptr, ++ bool force_fallback) + { +- void *ptr; ++ struct snd_pcm_mmap_control *mmap_control; + int err; +- if (hw->sync_ptr_ioctl == 0) { +- ptr = mmap(NULL, page_align(sizeof(struct snd_pcm_mmap_control)), +- PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, +- hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); +- if (ptr == MAP_FAILED || ptr == NULL) { ++ ++ if (!force_fallback) { ++ mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), ++ PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, ++ hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); ++ if (mmap_control == MAP_FAILED || mmap_control == NULL) { + err = -errno; + SYSMSG("control mmap failed (%i)", err); + return err; + } +- hw->mmap_control = ptr; ++ } else { ++ mmap_control = &sync_ptr->c.control; + } + ++ hw->mmap_control = mmap_control; ++ + return 0; + } + +@@ -918,18 +931,14 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + return -ENOMEM; + memset(sync_ptr, 0, sizeof(*sync_ptr)); + +- hw->sync_ptr_ioctl = (int)force_fallback; +- +- err = map_status_data(hw, sync_ptr); +- if (err < 0) +- return err; +- +- err = map_control_data(hw); ++ hw->mmap_status_fallbacked = ++ map_status_data(hw, sync_ptr, force_fallback); ++ err = map_control_data(hw, sync_ptr, hw->mmap_status_fallbacked); + if (err < 0) + return err; + + /* Any fallback mode needs to keep the buffer. */ +- if (hw->sync_ptr_ioctl == 0) { ++ if (hw->mmap_status_fallbacked == 0) { + hw->sync_ptr = sync_ptr; + } else { + free(sync_ptr); +@@ -944,7 +953,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + offsetof(struct snd_pcm_mmap_status, hw_ptr)); + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); +- if (hw->sync_ptr_ioctl) { ++ if (hw->mmap_status_fallbacked) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); +@@ -957,7 +966,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + + static void unmap_status_data(snd_pcm_hw_t *hw) + { +- if (!hw->sync_ptr) { ++ if (!hw->mmap_status_fallbacked) { + if (munmap((void *)hw->mmap_status, + page_align(sizeof(*hw->mmap_status))) < 0) + SYSMSG("status munmap failed (%u)", errno); +@@ -966,7 +975,7 @@ static void unmap_status_data(snd_pcm_hw_t *hw) + + static void unmap_control_data(snd_pcm_hw_t *hw) + { +- if (!hw->sync_ptr) { ++ if (!hw->mmap_status_fallbacked) { + if (munmap((void *)hw->mmap_control, + page_align(sizeof(*hw->mmap_control))) < 0) + SYSMSG("control munmap failed (%u)", errno); +@@ -978,11 +987,12 @@ static void unmap_status_and_control_data(snd_pcm_hw_t *hw) + unmap_status_data(hw); + unmap_control_data(hw); + +- if (hw->sync_ptr) ++ if (hw->mmap_status_fallbacked) + free(hw->sync_ptr); + + hw->mmap_status = NULL; + hw->mmap_control = NULL; ++ hw->mmap_status_fallbacked = false; + hw->sync_ptr = NULL; + } + +-- +2.13.5 + + +From 48bf3d3e964fbd34afd430632e8f2f5ca395d24c Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Sun, 25 Jun 2017 13:41:24 +0900 +Subject: [PATCH 14/39] pcm: hw: maintain fallback mode for control data + mapping independently + +Currently, failures of status/control data mapping are handled dependently. +However, it's not sure that one of the operations is failed when another +is failed. + +This commit adds a member into private data structure to maintain fallback +mode for control data mapping, independently of status data mapping. As a +result, we have four cases to handle status/control data: + +1. both of status/control data are mapped. +Nothing changed. A structure with alias of 'snd_pcm_hw_t' already has two +members to point the mapped area and in application runtime they're used +to refer/set status/control data. No need to call ioctl(2) with +SNDRV_PCM_IOCTL_SYNC_PTR to issue/query the data. + +2. both of status/control data are unmapped. +The two members point to allocated memory for fallback buffer. In +application runtime, the buffer is given as an argument for ioctl(2) with +SNDRV_PCM_IOCTL_SYNC_PTR to issue/query the data. + +3. status data is mapped only. +One of the two members is used to point the mapped area. Another points to +allocated memory for fallback buffer. In application runtime, the buffer +is used as an argument to execute ioctl(2) with SNDRV_PCM_IOCTL_SYNC_PTR +for the latter data, but the former data is already synchronized. + +4. control data is mapped only. +The same as the above. + +In design of ALSA PCM interface, userspace applications are not expected +to map the status data as writable. On the other hand, expected to map +the control data as writable. In a focus on the differences, we could +achieve to reduce calls of the ioctl(2) in a case that one of the +status/control data is successfully mapped and another is failed (case 3 +and 4). Especially, in current alsa-lib implementation, application +runtime queries state of runtime of PCM substream so often. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 37 ++++++++++++++++++++----------------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 78857941..5573fce2 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -95,6 +95,7 @@ typedef struct { + volatile struct snd_pcm_mmap_status * mmap_status; + struct snd_pcm_mmap_control *mmap_control; + bool mmap_status_fallbacked; ++ bool mmap_control_fallbacked; + struct snd_pcm_sync_ptr *sync_ptr; + + int period_event; +@@ -143,9 +144,11 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + +-static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) ++static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) + { +- return hw->sync_ptr ? sync_ptr1(hw, flags) : 0; ++ if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) ++ return sync_ptr1(hw, flags); ++ return 0; + } + + static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) +@@ -899,24 +902,24 @@ static bool map_control_data(snd_pcm_hw_t *hw, + bool force_fallback) + { + struct snd_pcm_mmap_control *mmap_control; +- int err; ++ bool fallbacked; + + if (!force_fallback) { + mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, + hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); +- if (mmap_control == MAP_FAILED || mmap_control == NULL) { +- err = -errno; +- SYSMSG("control mmap failed (%i)", err); +- return err; +- } +- } else { ++ } ++ ++ if (mmap_control == MAP_FAILED || mmap_control == NULL) { + mmap_control = &sync_ptr->c.control; ++ fallbacked = true; ++ } else { ++ fallbacked = false; + } + + hw->mmap_control = mmap_control; + +- return 0; ++ return fallbacked; + } + + static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) +@@ -933,12 +936,11 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + + hw->mmap_status_fallbacked = + map_status_data(hw, sync_ptr, force_fallback); +- err = map_control_data(hw, sync_ptr, hw->mmap_status_fallbacked); +- if (err < 0) +- return err; ++ hw->mmap_control_fallbacked = ++ map_control_data(hw, sync_ptr, force_fallback); + + /* Any fallback mode needs to keep the buffer. */ +- if (hw->mmap_status_fallbacked == 0) { ++ if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) { + hw->sync_ptr = sync_ptr; + } else { + free(sync_ptr); +@@ -953,7 +955,7 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + offsetof(struct snd_pcm_mmap_status, hw_ptr)); + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); +- if (hw->mmap_status_fallbacked) { ++ if (hw->mmap_control_fallbacked) { + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); +@@ -975,7 +977,7 @@ static void unmap_status_data(snd_pcm_hw_t *hw) + + static void unmap_control_data(snd_pcm_hw_t *hw) + { +- if (!hw->mmap_status_fallbacked) { ++ if (!hw->mmap_control_fallbacked) { + if (munmap((void *)hw->mmap_control, + page_align(sizeof(*hw->mmap_control))) < 0) + SYSMSG("control munmap failed (%u)", errno); +@@ -987,12 +989,13 @@ static void unmap_status_and_control_data(snd_pcm_hw_t *hw) + unmap_status_data(hw); + unmap_control_data(hw); + +- if (hw->mmap_status_fallbacked) ++ if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) + free(hw->sync_ptr); + + hw->mmap_status = NULL; + hw->mmap_control = NULL; + hw->mmap_status_fallbacked = false; ++ hw->mmap_control_fallbacked = false; + hw->sync_ptr = NULL; + } + +-- +2.13.5 + + +From 8ef3805f1b80a6c6059e0d9efd404fe32697db15 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 20 Jun 2017 14:21:20 +0200 +Subject: [PATCH 15/39] pcm: hw: Call USER_PVERSION ioctl at open + +Up from the new PCM protocol 2.0.14, user-space can inform the +protocol version it supports to kernel, so that the kernel may switch +its behavior depending on it. Add this ioctl call in the PCM hw +plugin at opening. + +The patch contains also the addition of SNDRV_PCM_INFO_SYNC_APPLPTR +carried from the upstream kernel commit 42f945970af9 ("ALSA: pcm: Add +the explicit appl_ptr sync support"), as well as the trivial change +(an addition of comma) to sync with the kernel asound.h. + +Reviewed-by: Takashi Sakamoto +Tested-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + include/sound/asound.h | 6 ++++-- + src/pcm/pcm_hw.c | 10 ++++++++++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/include/sound/asound.h b/include/sound/asound.h +index fb8d7d7e..1949923a 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -111,7 +111,7 @@ enum { + SNDRV_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ + + /* Don't forget to change the following: */ +- SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE, ++ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE + }; + + struct snd_hwdep_info { +@@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image { + * * + *****************************************************************************/ + +-#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) ++#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) + + typedef unsigned long snd_pcm_uframes_t; + typedef signed long snd_pcm_sframes_t; +@@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t; + #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ + #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ + #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ ++#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ + #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ + #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ + #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ +@@ -563,6 +564,7 @@ enum { + #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) + #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) + #define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) ++#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) + #define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) + #define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) + #define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 5573fce2..64188b22 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -1494,6 +1494,16 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, + if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_PCM_VERSION_MAX)) + return -SND_ERROR_INCOMPATIBLE_VERSION; + ++ if (SNDRV_PROTOCOL_VERSION(2, 0, 14) <= ver) { ++ /* inform the protocol version we're supporting */ ++ unsigned int user_ver = SNDRV_PCM_VERSION; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_USER_PVERSION, &user_ver) < 0) { ++ ret = -errno; ++ SNDMSG("USER_PVERSION failed\n"); ++ return ret; ++ } ++ } ++ + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + if (SNDRV_PROTOCOL_VERSION(2, 0, 9) <= ver) { + struct timespec timespec; +-- +2.13.5 + + +From ec16d21f86abbc23a56abeed0419a5a863ee5400 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 19:50:00 +0900 +Subject: [PATCH 16/39] pcm: hw: fix to initialize function local variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit is to fix below warning. + +pcm_hw.c: In function ‘snd1_pcm_hw_open_fd’: +pcm_hw.c:955:33: warning: ‘mmap_control’ may be used uninitialized in this function [-Wmaybe-uninitialized] + if (mmap_control == MAP_FAILED || mmap_control == NULL) { + ^ +pcm_hw.c:946:31: note: ‘mmap_control’ was declared here + struct snd_pcm_mmap_control *mmap_control; + ^~~~~~~~~~~~ + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 64188b22..e0931577 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -904,6 +904,7 @@ static bool map_control_data(snd_pcm_hw_t *hw, + struct snd_pcm_mmap_control *mmap_control; + bool fallbacked; + ++ mmap_control = MAP_FAILED; + if (!force_fallback) { + mmap_control = mmap(NULL, page_align(sizeof(*mmap_control)), + PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, +-- +2.13.5 + + +From 84beecc71ec508feb32bdf3fd1655dc7d0badfac Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Fri, 30 Jun 2017 14:14:55 +0100 +Subject: [PATCH 17/39] topology: Add support for new widget types + +Add topology support for new DSP widget types. This allows the new +widgets to be added to the driver and firmware DAPM graphs. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + include/sound/asoc.h | 10 +++++++++- + src/topology/dapm.c | 8 ++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/include/sound/asoc.h b/include/sound/asoc.h +index 082c5429..0f5d9f9a 100644 +--- a/include/sound/asoc.h ++++ b/include/sound/asoc.h +@@ -70,7 +70,15 @@ + #define SND_SOC_TPLG_DAPM_DAI_IN 13 + #define SND_SOC_TPLG_DAPM_DAI_OUT 14 + #define SND_SOC_TPLG_DAPM_DAI_LINK 15 +-#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DAI_LINK ++#define SND_SOC_TPLG_DAPM_BUFFER 16 ++#define SND_SOC_TPLG_DAPM_SCHEDULER 17 ++#define SND_SOC_TPLG_DAPM_EFFECT 18 ++#define SND_SOC_TPLG_DAPM_SIGGEN 19 ++#define SND_SOC_TPLG_DAPM_SRC 20 ++#define SND_SOC_TPLG_DAPM_ASRC 21 ++#define SND_SOC_TPLG_DAPM_ENCODER 22 ++#define SND_SOC_TPLG_DAPM_DECODER 23 ++#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DECODER + + /* Header magic number and string sizes */ + #define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */ +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 6af750b9..66892a66 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -38,6 +38,14 @@ static const struct map_elem widget_map[] = { + {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN}, + {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT}, + {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK}, ++ {"buffer", SND_SOC_TPLG_DAPM_BUFFER}, ++ {"scheduler", SND_SOC_TPLG_DAPM_SCHEDULER}, ++ {"effect", SND_SOC_TPLG_DAPM_EFFECT}, ++ {"siggen", SND_SOC_TPLG_DAPM_SIGGEN}, ++ {"src", SND_SOC_TPLG_DAPM_SRC}, ++ {"asrc", SND_SOC_TPLG_DAPM_ASRC}, ++ {"encoder", SND_SOC_TPLG_DAPM_ENCODER}, ++ {"decoder", SND_SOC_TPLG_DAPM_DECODER}, + }; + + static int lookup_widget(const char *w) +-- +2.13.5 + + +From 5c9582b8b428f3dbacb9e2fc32924f55c38efe8d Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Fri, 30 Jun 2017 14:14:56 +0100 +Subject: [PATCH 18/39] topology: improve verbose output for block output. + +Show index and full DAPm route in verbose output. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/builder.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/src/topology/builder.c b/src/topology/builder.c +index ca5cbe1a..997df0c7 100644 +--- a/src/topology/builder.c ++++ b/src/topology/builder.c +@@ -67,9 +67,10 @@ static int write_block_header(snd_tplg_t *tplg, unsigned int type, + exit(-EINVAL); + } + +- verbose(tplg, " header type %d size 0x%lx/%ld vendor %d " +- "version %d\n", type, (long unsigned int)payload_size, +- (long int)payload_size, vendor_type, version); ++ verbose(tplg, " header index %d type %d count %d size 0x%lx/%ld vendor %d " ++ "version %d\n", index, type, count, ++ (long unsigned int)payload_size, (long int)payload_size, ++ vendor_type, version); + + tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr); + +@@ -119,8 +120,10 @@ static int write_elem_block(snd_tplg_t *tplg, + verbose(tplg, " %s '%s': write %d bytes\n", + obj_name, elem->id, elem->size); + else +- verbose(tplg, " %s '%s': write %d bytes\n", +- obj_name, elem->route->source, elem->size); ++ verbose(tplg, " %s '%s -> %s -> %s': write %d bytes\n", ++ obj_name, elem->route->source, ++ elem->route->control, ++ elem->route->sink, elem->size); + + wsize = write(tplg->out_fd, elem->obj, elem->size); + if (wsize < 0) { +-- +2.13.5 + + +From 4396c83a4d572c32e88a6eb9d3f48240bf89da8e Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:00:26 +0900 +Subject: [PATCH 19/39] pcm: hw: minor refactoring for initialization of + control data + +At failure of control data mapping, alsa-lib goes to fallback mode. In +this mode, a buffer is kept in user space and executes ioctl(2) with +SNDRV_PCM_IOCTL_SYNC_PTR for the buffer to synchronize the control data. + +In current implementation, no helper function is used for initialize +the control data. This commit use an proper helper function instead of +a direct call of ioctl(2). + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index e0931577..f03bc589 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -957,11 +957,9 @@ static int map_status_and_control_data(snd_pcm_t *pcm, bool force_fallback) + snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, + SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (hw->mmap_control_fallbacked) { +- if (ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr) < 0) { +- err = -errno; +- SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed (%i)", err); ++ err = sync_ptr1(hw, 0); ++ if (err < 0) + return err; +- } + } + + return 0; +-- +2.13.5 + + +From ce0905c3ca50e143cadf7b0b70f3049ef8024dab Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:24 +0900 +Subject: [PATCH 20/39] pcm: hw: add a helper function to query status/control + data + +When executing ioctl(2) with some commands, applications can request +ALSA PCM core to change appl_ptr in kernel space. Below is a list of +such operations: + - SNDRV_PCM_IOCTL_PREPARE + - SNDRV_PCM_IOCTL_RESET + - SNDRV_PCM_IOCTL_REWIND + - SNDRV_PCM_IOCTL_FORWARD + - SNDRV_PCM_IOCTL_WRITEI_FRAMES + - SNDRV_PCM_IOCTL_WRITEN_FRAMES + - SNDRV_PCM_IOCTL_READI_FRAMES + - SNDRV_PCM_IOCTL_READN_FRAMES + +After these operations, the value of appl_ptr should be synchronized +between kernel/user spaces. + +This commit adds a helper function to query status and control data +without issuing the control data just in fallback from failure of control +mapping. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 46 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 34 insertions(+), 12 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index f03bc589..9963523c 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -151,6 +151,20 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + ++static int query_status_and_control_data(snd_pcm_hw_t *hw) ++{ ++ if (!hw->mmap_control_fallbacked) ++ return 0; ++ ++ /* ++ * Query both of control/status data to avoid unexpected change of ++ * control data in kernel space. ++ */ ++ return sync_ptr1(hw, ++ SNDRV_PCM_SYNC_PTR_APPL | ++ SNDRV_PCM_SYNC_PTR_AVAIL_MIN); ++} ++ + static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) + { + if (hw->period_timer_need_poll) { +@@ -601,7 +615,7 @@ static int snd_pcm_hw_prepare(snd_pcm_t *pcm) + SYSMSG("SNDRV_PCM_IOCTL_PREPARE failed (%i)", err); + return err; + } +- return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); ++ return query_status_and_control_data(hw); + } + + static int snd_pcm_hw_reset(snd_pcm_t *pcm) +@@ -613,7 +627,7 @@ static int snd_pcm_hw_reset(snd_pcm_t *pcm) + SYSMSG("SNDRV_PCM_IOCTL_RESET failed (%i)", err); + return err; + } +- return sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); ++ return query_status_and_control_data(hw); + } + + static int snd_pcm_hw_start(snd_pcm_t *pcm) +@@ -688,7 +702,7 @@ static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t fra + SYSMSG("SNDRV_PCM_IOCTL_REWIND failed (%i)", err); + return err; + } +- err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); ++ err = query_status_and_control_data(hw); + if (err < 0) + return err; + return frames; +@@ -709,7 +723,7 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr + SYSMSG("SNDRV_PCM_IOCTL_FORWARD failed (%i)", err); + return err; + } +- err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL); ++ err = query_status_and_control_data(hw); + if (err < 0) + return err; + return frames; +@@ -805,8 +819,10 @@ static snd_pcm_sframes_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, s + xferi.buf = (char*) buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ +- err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi); +- err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &xferi) < 0) ++ err = -errno; ++ else ++ err = query_status_and_control_data(hw); + #ifdef DEBUG_RW + fprintf(stderr, "hw_writei: frames = %li, xferi.result = %li, err = %i\n", size, xferi.result, err); + #endif +@@ -824,8 +840,10 @@ static snd_pcm_sframes_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_ + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; +- err = ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern); +- err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_WRITEN_FRAMES, &xfern) < 0) ++ err = -errno; ++ else ++ err = query_status_and_control_data(hw); + #ifdef DEBUG_RW + fprintf(stderr, "hw_writen: frames = %li, result = %li, err = %i\n", size, xfern.result, err); + #endif +@@ -843,8 +861,10 @@ static snd_pcm_sframes_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_ + xferi.buf = buffer; + xferi.frames = size; + xferi.result = 0; /* make valgrind happy */ +- err = ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi); +- err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_READI_FRAMES, &xferi) < 0) ++ err = -errno; ++ else ++ err = query_status_and_control_data(hw); + #ifdef DEBUG_RW + fprintf(stderr, "hw_readi: frames = %li, result = %li, err = %i\n", size, xferi.result, err); + #endif +@@ -862,8 +882,10 @@ static snd_pcm_sframes_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_u + memset(&xfern, 0, sizeof(xfern)); /* make valgrind happy */ + xfern.bufs = bufs; + xfern.frames = size; +- err = ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern); +- err = err >= 0 ? sync_ptr(hw, SNDRV_PCM_SYNC_PTR_APPL) : -errno; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_READN_FRAMES, &xfern) < 0) ++ err = -errno; ++ else ++ err = query_status_and_control_data(hw); + #ifdef DEBUG_RW + fprintf(stderr, "hw_readn: frames = %li, result = %li, err = %i\n", size, xfern.result, err); + #endif +-- +2.13.5 + + +From 78f3165a9e82d6f5e83e0e7075cdd96b49f9f401 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:25 +0900 +Subject: [PATCH 21/39] pcm: hw: add a helper function just to query status + data + +When mapping status data successfully, mapped page includes status data +for applications. In this case, applications have no need to call ioctl(2) +with SNDRV_PCM_IOCTL_SYNC_PTR. However, in current implementation, when +map of control data is unavailable, applications execute the ioctl(2). +This is inconvenient for some cases that applications require to query +status only. + +This commit adds a helper function to query status data without issuing +the control in fallback mode from failure of status mmap. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 9963523c..38d975af 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -165,6 +165,20 @@ static int query_status_and_control_data(snd_pcm_hw_t *hw) + SNDRV_PCM_SYNC_PTR_AVAIL_MIN); + } + ++static int query_status_data(snd_pcm_hw_t *hw) ++{ ++ if (!hw->mmap_status_fallbacked) ++ return 0; ++ ++ /* ++ * Query both of control/status data to avoid unexpected change of ++ * control data in kernel space. ++ */ ++ return sync_ptr1(hw, ++ SNDRV_PCM_SYNC_PTR_APPL | ++ SNDRV_PCM_SYNC_PTR_AVAIL_MIN); ++} ++ + static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw) + { + if (hw->period_timer_need_poll) { +@@ -349,7 +363,7 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + params->info &= ~0xf0000000; + if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) + params->info |= SND_PCM_INFO_MONOTONIC; +- return sync_ptr(hw, 0); ++ return query_status_data(hw); + } + + static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw) +@@ -556,7 +570,7 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + static snd_pcm_state_t snd_pcm_hw_state(snd_pcm_t *pcm) + { + snd_pcm_hw_t *hw = pcm->private_data; +- int err = sync_ptr(hw, 0); ++ int err = query_status_data(hw); + if (err < 0) + return err; + return (snd_pcm_state_t) hw->mmap_status->state; +@@ -1064,7 +1078,7 @@ static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm) + snd_pcm_hw_t *hw = pcm->private_data; + snd_pcm_uframes_t avail; + +- sync_ptr(hw, 0); ++ query_status_data(hw); + avail = snd_pcm_mmap_avail(pcm); + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: +-- +2.13.5 + + +From 8a3df40bce2ae3fd9e9dfdf979b2c672754e0b93 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:26 +0900 +Subject: [PATCH 22/39] pcm: hw: add a helper function to request hwsync + without side-effects + +SNDRV_PCM_IOCTL_SYNC_PTR command for ioctl(2) with +SNDRV_PCM_SYNC_PTR_HWSYNC flag has an effect to update hw_ptr. +This is an alternative of SNDRV_PCM_IOCTL_HWSYNC but caller can get +current status simultaneously. + +This commit adds a helper function just to issue hwsync. To avoid +side-effect to change appl_ptr and avail_min, this commit uses +SNDRV_PCM_SYNC_PTR_APPL and SNDRV_PCM_SYNC_PTR_AVAIL_MIN flags. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 38d975af..8455baaf 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -151,6 +151,21 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + ++static int request_hwsync(snd_pcm_hw_t *hw) ++{ ++ if (!hw->mmap_status_fallbacked) ++ return 0; ++ ++ /* ++ * Query both of control/status data to avoid unexpected change of ++ * control data in kernel space. ++ */ ++ return sync_ptr1(hw, ++ SNDRV_PCM_SYNC_PTR_HWSYNC | ++ SNDRV_PCM_SYNC_PTR_APPL | ++ SNDRV_PCM_SYNC_PTR_AVAIL_MIN); ++} ++ + static int query_status_and_control_data(snd_pcm_hw_t *hw) + { + if (!hw->mmap_control_fallbacked) +@@ -593,8 +608,8 @@ static int snd_pcm_hw_hwsync(snd_pcm_t *pcm) + snd_pcm_hw_t *hw = pcm->private_data; + int fd = hw->fd, err; + if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) { +- if (hw->sync_ptr) { +- err = sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); ++ if (hw->mmap_status_fallbacked) { ++ err = request_hwsync(hw); + if (err < 0) + return err; + } else { +-- +2.13.5 + + +From de9fe69e40e6b705aeae9aa8d1408736d4a1e563 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:27 +0900 +Subject: [PATCH 23/39] pcm: hw: add a helper function to issue appl_ptr + without side-effects + +After starting, PCM substream shift its state to running and applications +can move appl_ptr by several ways. When status and control data of runtime +of the PCM substream is not mapped, the applications should issue appl_ptr +to kernel land. In this case, when any PCM frames is handled by mmap +operation, the applications should issue appl_ptr to update. + +This commit adds a helper function for this purpose. To avoid unexpected +change of avail_min, this commit uses a flag just to update appl_ptr. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 8455baaf..51512306 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -151,6 +151,15 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + ++static int issue_applptr(snd_pcm_hw_t *hw) ++{ ++ if (!hw->mmap_control_fallbacked) ++ return 0; ++ ++ /* Avoid unexpected change of avail_min in kernel space. */ ++ return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_AVAIL_MIN); ++} ++ + static int request_hwsync(snd_pcm_hw_t *hw) + { + if (!hw->mmap_status_fallbacked) +@@ -667,7 +676,7 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm) + assert(pcm->stream != SND_PCM_STREAM_PLAYBACK || + snd_pcm_mmap_playback_hw_avail(pcm) > 0); + #endif +- sync_ptr(hw, 0); ++ issue_applptr(hw); + if (ioctl(hw->fd, SNDRV_PCM_IOCTL_START) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_START failed (%i)", err); +@@ -1081,7 +1090,7 @@ static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, + snd_pcm_hw_t *hw = pcm->private_data; + + snd_pcm_mmap_appl_forward(pcm, size); +- sync_ptr(hw, 0); ++ issue_applptr(hw); + #ifdef DEBUG_MMAP + fprintf(stderr, "appl_forward: hw_ptr = %li, appl_ptr = %li, size = %li\n", *pcm->hw.ptr, *pcm->appl.ptr, size); + #endif +-- +2.13.5 + + +From cea81cbdc2e7be344a34992ad6adef451a759840 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:28 +0900 +Subject: [PATCH 24/39] pcm: hw: add a helper function to issue avail_min + without side-effects + +At present, applications can change avail_min parameter of PCM substream +by two ways; via mapped control data, and by executing ioctl(2) with +SNDRV_PCM_IOCTL_SYNC_PTR. The former is available in a case that the +applications map the data successfully. + +When utilizing alsa-lib API, the above is done by a call of +'snd_pcm_sw_params()' to hw PCM plugin. In current implementation, this +call has an side-effect to issue appl_ptr unexpectedly. + +This commit adds a helper function to issue avail_min without the +side-effect. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 51512306..9c8fc3f6 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -151,6 +151,15 @@ static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + ++static int issue_avail_min(snd_pcm_hw_t *hw) ++{ ++ if (!hw->mmap_control_fallbacked) ++ return 0; ++ ++ /* Avoid unexpected change of applptr in kernel space. */ ++ return sync_ptr1(hw, SNDRV_PCM_SYNC_PTR_APPL); ++} ++ + static int issue_applptr(snd_pcm_hw_t *hw) + { + if (!hw->mmap_control_fallbacked) +@@ -506,7 +515,7 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) + params->silence_size == pcm->silence_size && + old_period_event == hw->period_event) { + hw->mmap_control->avail_min = params->avail_min; +- return sync_ptr(hw, 0); ++ return issue_avail_min(hw); + } + if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW && + hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { +-- +2.13.5 + + +From a9ec1a6f687a6cb4f14d3f093c2ee020b610e12d Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 30 Jun 2017 20:37:29 +0900 +Subject: [PATCH 25/39] pcm: hw: remove superfluous code to call of + SNDRV_PCM_IOCTL_SYNC_PTR in snd_pcm_hw_forward() + +SNDRV_PCM_IOCTL_SYNC_PTR command was introduced to PCM protocol/interface +in its version 2.0.7, however this command is used in a branch for the +newer version protocol/interface in snd_pcm_hw_forward(). + +This commit removes the superfluous code as a part of work for code +refactoring. + +Fixes: eafb4925124b ("- added SYNC_PTR ioctl support for pcm_hw plugin") +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 9c8fc3f6..16d45e74 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -144,13 +144,6 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags) + return 0; + } + +-static int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags) +-{ +- if (hw->mmap_status_fallbacked || hw->mmap_control_fallbacked) +- return sync_ptr1(hw, flags); +- return 0; +-} +- + static int issue_avail_min(snd_pcm_hw_t *hw) + { + if (!hw->mmap_control_fallbacked) +@@ -777,9 +770,6 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr + } else { + snd_pcm_sframes_t avail; + +- err = sync_ptr(hw, SNDRV_PCM_SYNC_PTR_HWSYNC); +- if (err < 0) +- return err; + switch (FAST_PCM_STATE(hw)) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_DRAINING: +@@ -797,9 +787,6 @@ static snd_pcm_sframes_t snd_pcm_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t fr + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); +- err = sync_ptr(hw, 0); +- if (err < 0) +- return err; + return frames; + } + } +-- +2.13.5 + + +From 885c64bcc48f5734da964d2da2b9a5603d7b2c8b Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Wed, 12 Jul 2017 10:45:18 +0200 +Subject: [PATCH 26/39] cleanup: fix poll.h includes + +According POSIX[1] and linux manpage[2] the include is poll.h, not +sys/poll.h. + +This fixes the he following compiler warning when build with musl libc: + + /usr/include/sys/poll.h:1:2: warning: #warning redirecting incorrect #include to [-Wcpp] + #warning redirecting incorrect #include to + ^~~~~~~ + +Signed-off-by: Natanael Copa +Signed-off-by: Takashi Iwai +--- + aserver/aserver.c | 2 +- + include/asoundlib-head.h | 2 +- + include/local.h | 2 +- + src/control/control.c | 2 +- + src/control/control_shm.c | 2 +- + src/pcm/pcm.c | 2 +- + src/pcm/pcm_direct.c | 2 +- + src/pcm/pcm_mmap.c | 2 +- + src/pcm/pcm_share.c | 2 +- + src/pcm/pcm_shm.c | 2 +- + src/seq/seq.c | 2 +- + src/shmarea.c | 2 +- + 12 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/aserver/aserver.c b/aserver/aserver.c +index ac20706b..46f731a4 100644 +--- a/aserver/aserver.c ++++ b/aserver/aserver.c +@@ -20,7 +20,7 @@ + + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/include/asoundlib-head.h b/include/asoundlib-head.h +index 1ec611e5..21e32c6b 100644 +--- a/include/asoundlib-head.h ++++ b/include/asoundlib-head.h +@@ -35,6 +35,6 @@ + #include + #include + #include +-#include ++#include + #include + #include +diff --git a/include/local.h b/include/local.h +index 317f2e32..6a43a473 100644 +--- a/include/local.h ++++ b/include/local.h +@@ -47,7 +47,7 @@ + #error Header defining endianness not defined + #endif + #include +-#include ++#include + #include + #include + #if defined(__linux__) +diff --git a/src/control/control.c b/src/control/control.c +index 134ba4c8..6439b294 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -90,7 +90,7 @@ against the original design. + #include + #include + #include +-#include ++#include + #include + #include "control_local.h" + +diff --git a/src/control/control_shm.c b/src/control/control_shm.c +index bd07d4af..9a2e268b 100644 +--- a/src/control/control_shm.c ++++ b/src/control/control_shm.c +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 200b10c2..2b4ce8ec 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -651,7 +651,7 @@ playback devices. + #include + #include + #include +-#include ++#include + #include + #include + #include "pcm_local.h" +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 9fd376d8..393083f5 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -30,7 +30,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c +index 1948289c..4cf220a4 100644 +--- a/src/pcm/pcm_mmap.c ++++ b/src/pcm/pcm_mmap.c +@@ -22,7 +22,7 @@ + #include + #include + #include +-#include ++#include + #include + #ifdef HAVE_SYS_SHM_H + #include +diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c +index 5d8aaf21..21a57fc6 100644 +--- a/src/pcm/pcm_share.c ++++ b/src/pcm/pcm_share.c +@@ -34,7 +34,7 @@ + #include + #include + #include +-#include ++#include + #include + #include "pcm_local.h" + +diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c +index a815ac6b..4ee958c1 100644 +--- a/src/pcm/pcm_shm.c ++++ b/src/pcm/pcm_shm.c +@@ -36,7 +36,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +diff --git a/src/seq/seq.c b/src/seq/seq.c +index b206e2f8..d5ed1c6a 100644 +--- a/src/seq/seq.c ++++ b/src/seq/seq.c +@@ -777,7 +777,7 @@ void event_filter(snd_seq_t *seq, snd_seq_event_t *ev) + + */ + +-#include ++#include + #include "seq_local.h" + + /**************************************************************************** +diff --git a/src/shmarea.c b/src/shmarea.c +index 9843aa8b..eaa71f00 100644 +--- a/src/shmarea.c ++++ b/src/shmarea.c +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include "list.h" +-- +2.13.5 + + +From adab355f35c8fcb424b1336043634cf9a6856515 Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Fri, 14 Jul 2017 16:18:11 +0200 +Subject: [PATCH 27/39] cleanup: Use uint*_t instead of u_int*_t everythwere + +Use the standard uint{8,16,32,64}_t everywhere instead of the +non-standard u_int{8,16,32,64}_t. + +This changes the types in the public headers and removes the u_int*_t +defines. This may break things. However, indentifiers ending with _t are +reserved by POSIX[1]; defining those can lead to undefined behavior. + +So if you rely on alsa-lib defining those for you, then you want the +compiler to error so things can be fixed properly. + +[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02_02 + +Signed-off-by: Natanael Copa +Signed-off-by: Takashi Iwai +--- + include/pcm.h | 10 ++- + include/type_compat.h | 12 --- + src/pcm/interval.c | 4 +- + src/pcm/mask_inline.h | 6 +- + src/pcm/pcm.c | 26 +++---- + src/pcm/pcm_iec958.c | 12 +-- + src/pcm/pcm_linear.c | 2 +- + src/pcm/pcm_misc.c | 42 +++++------ + src/pcm/pcm_rate_linear.c | 4 +- + src/pcm/pcm_route.c | 2 +- + src/pcm/plugin_ops.h | 182 +++++++++++++++++++++++----------------------- + 11 files changed, 146 insertions(+), 156 deletions(-) + +diff --git a/include/pcm.h b/include/pcm.h +index 0be1a321..d44de54b 100644 +--- a/include/pcm.h ++++ b/include/pcm.h +@@ -33,6 +33,8 @@ + extern "C" { + #endif + ++#include ++ + /** + * \defgroup PCM PCM Interface + * See the \ref pcm page for more details. +@@ -1108,10 +1110,10 @@ int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ + int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ + snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian); + ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); +-u_int8_t snd_pcm_format_silence(snd_pcm_format_t format); +-u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format); +-u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format); +-u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format); ++uint8_t snd_pcm_format_silence(snd_pcm_format_t format); ++uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format); ++uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format); ++uint64_t snd_pcm_format_silence_64(snd_pcm_format_t format); + int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int samples); + + snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes); +diff --git a/include/type_compat.h b/include/type_compat.h +index 0c10aed7..35973b1e 100644 +--- a/include/type_compat.h ++++ b/include/type_compat.h +@@ -47,18 +47,6 @@ + #ifndef __le64 + #define __le64 uint64_t + #endif +-#ifndef u_int8_t +-#define u_int8_t uint8_t +-#endif +-#ifndef u_int16_t +-#define u_int16_t uint16_t +-#endif +-#ifndef u_int32_t +-#define u_int32_t uint32_t +-#endif +-#ifndef u_int32_t +-#define u_int32_t uint64_t +-#endif + #ifndef __kernel_pid_t + #define __kernel_pid_t pid_t + #endif +diff --git a/src/pcm/interval.c b/src/pcm/interval.c +index 6e398084..74ec3204 100644 +--- a/src/pcm/interval.c ++++ b/src/pcm/interval.c +@@ -26,7 +26,7 @@ + #include + #include "pcm_local.h" + +-static inline void div64_32(u_int64_t *n, u_int32_t d, u_int32_t *rem) ++static inline void div64_32(uint64_t *n, uint32_t d, uint32_t *rem) + { + *rem = *n % d; + *n /= d; +@@ -88,7 +88,7 @@ static inline unsigned int sub(unsigned int a, unsigned int b) + static inline unsigned int muldiv32(unsigned int a, unsigned int b, + unsigned int c, unsigned int *r) + { +- u_int64_t n = (u_int64_t) a * b; ++ uint64_t n = (uint64_t) a * b; + if (c == 0) { + assert(n > 0); + *r = 0; +diff --git a/src/pcm/mask_inline.h b/src/pcm/mask_inline.h +index f656568d..04c7ee6e 100644 +--- a/src/pcm/mask_inline.h ++++ b/src/pcm/mask_inline.h +@@ -29,7 +29,7 @@ + #define MASK_OFS(i) ((i) >> 5) + #define MASK_BIT(i) (1U << ((i) & 31)) + +-MASK_INLINE unsigned int ld2(u_int32_t v) ++MASK_INLINE unsigned int ld2(uint32_t v) + { + unsigned r = 0; + +@@ -54,7 +54,7 @@ MASK_INLINE unsigned int ld2(u_int32_t v) + return r; + } + +-MASK_INLINE unsigned int hweight32(u_int32_t v) ++MASK_INLINE unsigned int hweight32(uint32_t v) + { + v = (v & 0x55555555) + ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); +@@ -75,7 +75,7 @@ MASK_INLINE void snd_mask_none(snd_mask_t *mask) + + MASK_INLINE void snd_mask_any(snd_mask_t *mask) + { +- memset(mask, 0xff, MASK_SIZE * sizeof(u_int32_t)); ++ memset(mask, 0xff, MASK_SIZE * sizeof(uint32_t)); + } + + MASK_INLINE int snd_mask_empty(const snd_mask_t *mask) +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 2b4ce8ec..fc7bd52c 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -2894,7 +2894,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + char *dst; + unsigned int dst_step; + int width; +- u_int64_t silence; ++ uint64_t silence; + if (!dst_area->addr) + return 0; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); +@@ -2902,7 +2902,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + silence = snd_pcm_format_silence_64(format); + if (dst_area->step == (unsigned int) width) { + unsigned int dwords = samples * width / 64; +- u_int64_t *dstp = (u_int64_t *)dst; ++ uint64_t *dstp = (uint64_t *)dst; + samples -= dwords * 64 / width; + while (dwords-- > 0) + *dstp++ = silence; +@@ -2912,8 +2912,8 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + dst_step = dst_area->step / 8; + switch (width) { + case 4: { +- u_int8_t s0 = silence & 0xf0; +- u_int8_t s1 = silence & 0x0f; ++ uint8_t s0 = silence & 0xf0; ++ uint8_t s1 = silence & 0x0f; + int dstbit = dst_area->first % 8; + int dstbit_step = dst_area->step % 8; + while (samples-- > 0) { +@@ -2934,7 +2934,7 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + break; + } + case 8: { +- u_int8_t sil = silence; ++ uint8_t sil = silence; + while (samples-- > 0) { + *dst = sil; + dst += dst_step; +@@ -2942,9 +2942,9 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + break; + } + case 16: { +- u_int16_t sil = silence; ++ uint16_t sil = silence; + while (samples-- > 0) { +- *(u_int16_t*)dst = sil; ++ *(uint16_t*)dst = sil; + dst += dst_step; + } + break; +@@ -2961,16 +2961,16 @@ int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes + #endif + break; + case 32: { +- u_int32_t sil = silence; ++ uint32_t sil = silence; + while (samples-- > 0) { +- *(u_int32_t*)dst = sil; ++ *(uint32_t*)dst = sil; + dst += dst_step; + } + break; + } + case 64: { + while (samples-- > 0) { +- *(u_int64_t*)dst = silence; ++ *(uint64_t*)dst = silence; + dst += dst_step; + } + break; +@@ -3114,7 +3114,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t + } + case 16: { + while (samples-- > 0) { +- *(u_int16_t*)dst = *(const u_int16_t*)src; ++ *(uint16_t*)dst = *(const uint16_t*)src; + src += src_step; + dst += dst_step; + } +@@ -3131,7 +3131,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t + break; + case 32: { + while (samples-- > 0) { +- *(u_int32_t*)dst = *(const u_int32_t*)src; ++ *(uint32_t*)dst = *(const uint32_t*)src; + src += src_step; + dst += dst_step; + } +@@ -3139,7 +3139,7 @@ int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t + } + case 64: { + while (samples-- > 0) { +- *(u_int64_t*)dst = *(const u_int64_t*)src; ++ *(uint64_t*)dst = *(const uint64_t*)src; + src += src_step; + dst += dst_step; + } +diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c +index 86ac9cfd..115092de 100644 +--- a/src/pcm/pcm_iec958.c ++++ b/src/pcm/pcm_iec958.c +@@ -102,7 +102,7 @@ static unsigned int iec958_parity(unsigned int data) + * 31 = parity + */ + +-static inline u_int32_t iec958_subframe(snd_pcm_iec958_t *iec, u_int32_t data, int channel) ++static inline uint32_t iec958_subframe(snd_pcm_iec958_t *iec, uint32_t data, int channel) + { + unsigned int byte = iec->counter >> 3; + unsigned int mask = 1 << (iec->counter - (byte << 3)); +@@ -132,7 +132,7 @@ static inline u_int32_t iec958_subframe(snd_pcm_iec958_t *iec, u_int32_t data, i + return data; + } + +-static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, u_int32_t data) ++static inline int32_t iec958_to_s32(snd_pcm_iec958_t *iec, uint32_t data) + { + if (iec->byteswap) + data = bswap_32(data); +@@ -155,7 +155,7 @@ static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec, + void *put = put32_labels[iec->getput_idx]; + unsigned int channel; + for (channel = 0; channel < channels; ++channel) { +- const u_int32_t *src; ++ const uint32_t *src; + char *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; +@@ -163,7 +163,7 @@ static void snd_pcm_iec958_decode(snd_pcm_iec958_t *iec, + const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); +- src_step = snd_pcm_channel_area_step(src_area) / sizeof(u_int32_t); ++ src_step = snd_pcm_channel_area_step(src_area) / sizeof(uint32_t); + dst_step = snd_pcm_channel_area_step(dst_area); + frames1 = frames; + while (frames1-- > 0) { +@@ -195,7 +195,7 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + int counter = iec->counter; + for (channel = 0; channel < channels; ++channel) { + const char *src; +- u_int32_t *dst; ++ uint32_t *dst; + int src_step, dst_step; + snd_pcm_uframes_t frames1; + const snd_pcm_channel_area_t *src_area = &src_areas[channel]; +@@ -203,7 +203,7 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + src = snd_pcm_channel_area_addr(src_area, src_offset); + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + src_step = snd_pcm_channel_area_step(src_area); +- dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(u_int32_t); ++ dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(uint32_t); + frames1 = frames; + iec->counter = counter; + while (frames1-- > 0) { +diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c +index 50df7794..9b1d9638 100644 +--- a/src/pcm/pcm_linear.c ++++ b/src/pcm/pcm_linear.c +@@ -183,7 +183,7 @@ void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_ufra + void *get = get32_labels[get_idx]; + void *put = put32_labels[put_idx]; + unsigned int channel; +- u_int32_t sample = 0; ++ uint32_t sample = 0; + for (channel = 0; channel < channels; ++channel) { + const char *src; + char *dst; +diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c +index 7d2b05db..a321c87e 100644 +--- a/src/pcm/pcm_misc.c ++++ b/src/pcm/pcm_misc.c +@@ -387,7 +387,7 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) + * \param format Sample format + * \return silence 64 bit word + */ +-u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) ++uint64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + { + switch (format) { + case SNDRV_PCM_FORMAT_S8: +@@ -467,7 +467,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + { + union { + float f[2]; +- u_int64_t i; ++ uint64_t i; + } u; + u.f[0] = u.f[1] = 0.0; + #ifdef SNDRV_LITTLE_ENDIAN +@@ -480,7 +480,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + { + union { + double f; +- u_int64_t i; ++ uint64_t i; + } u; + u.f = 0.0; + #ifdef SNDRV_LITTLE_ENDIAN +@@ -493,7 +493,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + { + union { + float f[2]; +- u_int64_t i; ++ uint64_t i; + } u; + u.f[0] = u.f[1] = 0.0; + #ifdef SNDRV_LITTLE_ENDIAN +@@ -506,7 +506,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + { + union { + double f; +- u_int64_t i; ++ uint64_t i; + } u; + u.f = 0.0; + #ifdef SNDRV_LITTLE_ENDIAN +@@ -539,10 +539,10 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + * \param format Sample format + * \return silence 32 bit word + */ +-u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) ++uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format) + { + assert(snd_pcm_format_physical_width(format) <= 32); +- return (u_int32_t)snd_pcm_format_silence_64(format); ++ return (uint32_t)snd_pcm_format_silence_64(format); + } + + /** +@@ -550,10 +550,10 @@ u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) + * \param format Sample format + * \return silence 16 bit word + */ +-u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) ++uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format) + { + assert(snd_pcm_format_physical_width(format) <= 16); +- return (u_int16_t)snd_pcm_format_silence_64(format); ++ return (uint16_t)snd_pcm_format_silence_64(format); + } + + /** +@@ -561,10 +561,10 @@ u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) + * \param format Sample format + * \return silence 8 bit word + */ +-u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) ++uint8_t snd_pcm_format_silence(snd_pcm_format_t format) + { + assert(snd_pcm_format_physical_width(format) <= 8); +- return (u_int8_t)snd_pcm_format_silence_64(format); ++ return (uint8_t)snd_pcm_format_silence_64(format); + } + + /** +@@ -580,7 +580,7 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int + return 0; + switch (snd_pcm_format_physical_width(format)) { + case 4: { +- u_int8_t silence = snd_pcm_format_silence_64(format); ++ uint8_t silence = snd_pcm_format_silence_64(format); + unsigned int samples1; + if (samples % 2 != 0) + return -EINVAL; +@@ -589,13 +589,13 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int + break; + } + case 8: { +- u_int8_t silence = snd_pcm_format_silence_64(format); ++ uint8_t silence = snd_pcm_format_silence_64(format); + memset(data, silence, samples); + break; + } + case 16: { +- u_int16_t silence = snd_pcm_format_silence_64(format); +- u_int16_t *pdata = (u_int16_t *)data; ++ uint16_t silence = snd_pcm_format_silence_64(format); ++ uint16_t *pdata = (uint16_t *)data; + if (! silence) + memset(data, 0, samples * 2); + else { +@@ -605,8 +605,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int + break; + } + case 24: { +- u_int32_t silence = snd_pcm_format_silence_64(format); +- u_int8_t *pdata = (u_int8_t *)data; ++ uint32_t silence = snd_pcm_format_silence_64(format); ++ uint8_t *pdata = (uint8_t *)data; + if (! silence) + memset(data, 0, samples * 3); + else { +@@ -625,8 +625,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int + break; + } + case 32: { +- u_int32_t silence = snd_pcm_format_silence_64(format); +- u_int32_t *pdata = (u_int32_t *)data; ++ uint32_t silence = snd_pcm_format_silence_64(format); ++ uint32_t *pdata = (uint32_t *)data; + if (! silence) + memset(data, 0, samples * 4); + else { +@@ -636,8 +636,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int + break; + } + case 64: { +- u_int64_t silence = snd_pcm_format_silence_64(format); +- u_int64_t *pdata = (u_int64_t *)data; ++ uint64_t silence = snd_pcm_format_silence_64(format); ++ uint64_t *pdata = (uint64_t *)data; + if (! silence) + memset(data, 0, samples * 8); + else { +diff --git a/src/pcm/pcm_rate_linear.c b/src/pcm/pcm_rate_linear.c +index 70399e0d..b20c715a 100644 +--- a/src/pcm/pcm_rate_linear.c ++++ b/src/pcm/pcm_rate_linear.c +@@ -346,7 +346,7 @@ static int linear_init(void *obj, snd_pcm_rate_info_t *info) + rate->func = linear_shrink; + /* pitch is get_increment */ + } +- rate->pitch = (((u_int64_t)info->out.rate * LINEAR_DIV) + ++ rate->pitch = (((uint64_t)info->out.rate * LINEAR_DIV) + + (info->in.rate / 2)) / info->in.rate; + rate->channels = info->channels; + +@@ -363,7 +363,7 @@ static int linear_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) + struct rate_linear *rate = obj; + snd_pcm_uframes_t cframes; + +- rate->pitch = (((u_int64_t)info->out.period_size * LINEAR_DIV) + ++ rate->pitch = (((uint64_t)info->out.period_size * LINEAR_DIV) + + (info->in.period_size/2) ) / info->in.period_size; + + cframes = input_frames(rate, info->out.period_size); +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index 508d5b0f..1bb83d2f 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -190,7 +190,7 @@ static void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_ + const char *src; + char *dst; + int src_step, dst_step; +- u_int32_t sample = 0; ++ uint32_t sample = 0; + for (srcidx = 0; srcidx < ttable->nsrcs && srcidx < src_channels; ++srcidx) { + unsigned int channel = ttable->srcs[srcidx].channel; + if (channel >= src_channels) +diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h +index eb8c2c4f..69e7f2cf 100644 +--- a/src/pcm/plugin_ops.h ++++ b/src/pcm/plugin_ops.h +@@ -21,13 +21,13 @@ + + #ifndef SX_INLINES + #define SX_INLINES +-static inline u_int32_t sx24(u_int32_t x) ++static inline uint32_t sx24(uint32_t x) + { + if(x&0x00800000) + return x|0xFF000000; + return x&0x00FFFFFF; + } +-static inline u_int32_t sx24s(u_int32_t x) ++static inline uint32_t sx24s(uint32_t x) + { + if(x&0x00008000) + return x|0x000000FF; +@@ -35,10 +35,10 @@ static inline u_int32_t sx24s(u_int32_t x) + } + #endif + +-#define as_u8(ptr) (*(u_int8_t*)(ptr)) +-#define as_u16(ptr) (*(u_int16_t*)(ptr)) +-#define as_u32(ptr) (*(u_int32_t*)(ptr)) +-#define as_u64(ptr) (*(u_int64_t*)(ptr)) ++#define as_u8(ptr) (*(uint8_t*)(ptr)) ++#define as_u16(ptr) (*(uint16_t*)(ptr)) ++#define as_u32(ptr) (*(uint32_t*)(ptr)) ++#define as_u64(ptr) (*(uint64_t*)(ptr)) + #define as_s8(ptr) (*(int8_t*)(ptr)) + #define as_s16(ptr) (*(int16_t*)(ptr)) + #define as_s32(ptr) (*(int32_t*)(ptr)) +@@ -46,10 +46,10 @@ static inline u_int32_t sx24s(u_int32_t x) + #define as_float(ptr) (*(float_t*)(ptr)) + #define as_double(ptr) (*(double_t*)(ptr)) + +-#define as_u8c(ptr) (*(const u_int8_t*)(ptr)) +-#define as_u16c(ptr) (*(const u_int16_t*)(ptr)) +-#define as_u32c(ptr) (*(const u_int32_t*)(ptr)) +-#define as_u64c(ptr) (*(const u_int64_t*)(ptr)) ++#define as_u8c(ptr) (*(const uint8_t*)(ptr)) ++#define as_u16c(ptr) (*(const uint16_t*)(ptr)) ++#define as_u32c(ptr) (*(const uint32_t*)(ptr)) ++#define as_u64c(ptr) (*(const uint64_t*)(ptr)) + #define as_s8c(ptr) (*(const int8_t*)(ptr)) + #define as_s16c(ptr) (*(const int16_t*)(ptr)) + #define as_s32c(ptr) (*(const int32_t*)(ptr)) +@@ -57,18 +57,18 @@ static inline u_int32_t sx24s(u_int32_t x) + #define as_floatc(ptr) (*(const float_t*)(ptr)) + #define as_doublec(ptr) (*(const double_t*)(ptr)) + +-#define _get_triple_le(ptr) (*(u_int8_t*)(ptr) | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | (u_int32_t)*((u_int8_t*)(ptr) + 2) << 16) +-#define _get_triple_be(ptr) ((u_int32_t)*(u_int8_t*)(ptr) << 16 | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | *((u_int8_t*)(ptr) + 2)) ++#define _get_triple_le(ptr) (*(uint8_t*)(ptr) | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | (uint32_t)*((uint8_t*)(ptr) + 2) << 16) ++#define _get_triple_be(ptr) ((uint32_t)*(uint8_t*)(ptr) << 16 | (uint32_t)*((uint8_t*)(ptr) + 1) << 8 | *((uint8_t*)(ptr) + 2)) + #define _put_triple_le(ptr,val) do { \ +- u_int8_t *_tmp = (u_int8_t *)(ptr); \ +- u_int32_t _val = (val); \ ++ uint8_t *_tmp = (uint8_t *)(ptr); \ ++ uint32_t _val = (val); \ + _tmp[0] = _val; \ + _tmp[1] = _val >> 8; \ + _tmp[2] = _val >> 16; \ + } while(0) + #define _put_triple_be(ptr,val) do { \ +- u_int8_t *_tmp = (u_int8_t *)(ptr); \ +- u_int32_t _val = (val); \ ++ uint8_t *_tmp = (uint8_t *)(ptr); \ ++ uint32_t _val = (val); \ + _tmp[0] = _val >> 16; \ + _tmp[1] = _val >> 8; \ + _tmp[2] = _val; \ +@@ -243,45 +243,45 @@ static void *const conv_labels[4 * 2 * 2 * 4 * 2] = { + #ifdef CONV_END + while(0) { + conv_xxx1_xxx1: as_u8(dst) = as_u8c(src); goto CONV_END; +-conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8c(src) << 8; goto CONV_END; +-conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8c(src); goto CONV_END; +-conv_xxx1_x100: as_u32(dst) = sx24((u_int32_t)as_u8c(src) << 16); goto CONV_END; +-conv_xxx1_001x: as_u32(dst) = sx24s((u_int32_t)as_u8c(src) << 8); goto CONV_END; +-conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8c(src) << 24; goto CONV_END; +-conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8c(src); goto CONV_END; ++conv_xxx1_xx10: as_u16(dst) = (uint16_t)as_u8c(src) << 8; goto CONV_END; ++conv_xxx1_xx01: as_u16(dst) = (uint16_t)as_u8c(src); goto CONV_END; ++conv_xxx1_x100: as_u32(dst) = sx24((uint32_t)as_u8c(src) << 16); goto CONV_END; ++conv_xxx1_001x: as_u32(dst) = sx24s((uint32_t)as_u8c(src) << 8); goto CONV_END; ++conv_xxx1_1000: as_u32(dst) = (uint32_t)as_u8c(src) << 24; goto CONV_END; ++conv_xxx1_0001: as_u32(dst) = (uint32_t)as_u8c(src); goto CONV_END; + conv_xxx1_xxx9: as_u8(dst) = as_u8c(src) ^ 0x80; goto CONV_END; +-conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; +-conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8c(src) ^ 0x80); goto CONV_END; +-conv_xxx1_x900: as_u32(dst) = sx24((u_int32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; +-conv_xxx1_009x: as_u32(dst) = sx24s((u_int32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; +-conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; +-conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8c(src) ^ 0x80); goto CONV_END; ++conv_xxx1_xx90: as_u16(dst) = (uint16_t)(as_u8c(src) ^ 0x80) << 8; goto CONV_END; ++conv_xxx1_xx09: as_u16(dst) = (uint16_t)(as_u8c(src) ^ 0x80); goto CONV_END; ++conv_xxx1_x900: as_u32(dst) = sx24((uint32_t)(as_u8c(src) ^ 0x80) << 16); goto CONV_END; ++conv_xxx1_009x: as_u32(dst) = sx24s((uint32_t)(as_u8c(src) ^ 0x80) << 8); goto CONV_END; ++conv_xxx1_9000: as_u32(dst) = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto CONV_END; ++conv_xxx1_0009: as_u32(dst) = (uint32_t)(as_u8c(src) ^ 0x80); goto CONV_END; + conv_xx12_xxx1: as_u8(dst) = as_u16c(src) >> 8; goto CONV_END; + conv_xx12_xx12: as_u16(dst) = as_u16c(src); goto CONV_END; + conv_xx12_xx21: as_u16(dst) = bswap_16(as_u16c(src)); goto CONV_END; +-conv_xx12_x120: as_u32(dst) = sx24((u_int32_t)as_u16c(src) << 8); goto CONV_END; +-conv_xx12_021x: as_u32(dst) = sx24s((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +-conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16c(src) << 16; goto CONV_END; +-conv_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)); goto CONV_END; ++conv_xx12_x120: as_u32(dst) = sx24((uint32_t)as_u16c(src) << 8); goto CONV_END; ++conv_xx12_021x: as_u32(dst) = sx24s((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; ++conv_xx12_1200: as_u32(dst) = (uint32_t)as_u16c(src) << 16; goto CONV_END; ++conv_xx12_0021: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src)); goto CONV_END; + conv_xx12_xxx9: as_u8(dst) = (as_u16c(src) >> 8) ^ 0x80; goto CONV_END; + conv_xx12_xx92: as_u16(dst) = as_u16c(src) ^ 0x8000; goto CONV_END; + conv_xx12_xx29: as_u16(dst) = bswap_16(as_u16c(src)) ^ 0x80; goto CONV_END; +-conv_xx12_x920: as_u32(dst) = sx24((u_int32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; +-conv_xx12_029x: as_u32(dst) = sx24s((u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; +-conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; +-conv_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16c(src)) ^ 0x80); goto CONV_END; ++conv_xx12_x920: as_u32(dst) = sx24((uint32_t)(as_u16c(src) ^ 0x8000) << 8); goto CONV_END; ++conv_xx12_029x: as_u32(dst) = sx24s((uint32_t)(bswap_16(as_u16c(src)) ^ 0x80) << 8); goto CONV_END; ++conv_xx12_9200: as_u32(dst) = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto CONV_END; ++conv_xx12_0029: as_u32(dst) = (uint32_t)(bswap_16(as_u16c(src)) ^ 0x80); goto CONV_END; + conv_xx12_xxx2: as_u8(dst) = as_u16c(src) & 0xff; goto CONV_END; +-conv_xx12_x210: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; +-conv_xx12_012x: as_u32(dst) = sx24s((u_int32_t)as_u16c(src) << 8); goto CONV_END; +-conv_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; +-conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16c(src); goto CONV_END; ++conv_xx12_x210: as_u32(dst) = sx24((uint32_t)bswap_16(as_u16c(src)) << 8); goto CONV_END; ++conv_xx12_012x: as_u32(dst) = sx24s((uint32_t)as_u16c(src) << 8); goto CONV_END; ++conv_xx12_2100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src)) << 16; goto CONV_END; ++conv_xx12_0012: as_u32(dst) = (uint32_t)as_u16c(src); goto CONV_END; + conv_xx12_xxxA: as_u8(dst) = (as_u16c(src) ^ 0x80) & 0xff; goto CONV_END; + conv_xx12_xxA1: as_u16(dst) = bswap_16(as_u16c(src) ^ 0x80); goto CONV_END; + conv_xx12_xx1A: as_u16(dst) = as_u16c(src) ^ 0x80; goto CONV_END; +-conv_xx12_xA10: as_u32(dst) = sx24((u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +-conv_xx12_01Ax: as_u32(dst) = sx24s((u_int32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; +-conv_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; +-conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16c(src) ^ 0x80); goto CONV_END; ++conv_xx12_xA10: as_u32(dst) = sx24((uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 8); goto CONV_END; ++conv_xx12_01Ax: as_u32(dst) = sx24s((uint32_t)(as_u16c(src) ^ 0x80) << 8); goto CONV_END; ++conv_xx12_A100: as_u32(dst) = (uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto CONV_END; ++conv_xx12_001A: as_u32(dst) = (uint32_t)(as_u16c(src) ^ 0x80); goto CONV_END; + conv_x123_xxx1: as_u8(dst) = as_u32c(src) >> 16; goto CONV_END; + conv_x123_xx12: as_u16(dst) = as_u32c(src) >> 8; goto CONV_END; + conv_x123_xx21: as_u16(dst) = bswap_16(as_u32c(src) >> 8); goto CONV_END; +@@ -376,8 +376,8 @@ static void *const get16_labels[4 * 2 * 2 + 4 * 3] = { + + #ifdef GET16_END + while(0) { +-get16_1_10: sample = (u_int16_t)as_u8c(src) << 8; goto GET16_END; +-get16_1_90: sample = (u_int16_t)(as_u8c(src) ^ 0x80) << 8; goto GET16_END; ++get16_1_10: sample = (uint16_t)as_u8c(src) << 8; goto GET16_END; ++get16_1_90: sample = (uint16_t)(as_u8c(src) ^ 0x80) << 8; goto GET16_END; + get16_12_12: sample = as_u16c(src); goto GET16_END; + get16_12_92: sample = as_u16c(src) ^ 0x8000; goto GET16_END; + get16_12_21: sample = bswap_16(as_u16c(src)); goto GET16_END; +@@ -448,26 +448,26 @@ put16_12_12: as_u16(dst) = sample; goto PUT16_END; + put16_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT16_END; + put16_12_21: as_u16(dst) = bswap_16(sample); goto PUT16_END; + put16_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT16_END; +-put16_12_0120: as_u32(dst) = sx24((u_int32_t)sample << 8); goto PUT16_END; +-put16_12_0920: as_u32(dst) = sx24((u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +-put16_12_0210: as_u32(dst) = sx24s((u_int32_t)bswap_16(sample) << 8); goto PUT16_END; +-put16_12_0290: as_u32(dst) = sx24s((u_int32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; +-put16_12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT16_END; +-put16_12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT16_END; +-put16_12_0021: as_u32(dst) = (u_int32_t)bswap_16(sample); goto PUT16_END; +-put16_12_0029: as_u32(dst) = (u_int32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; +-put16_12_120: _put_triple(dst, (u_int32_t)sample << 8); goto PUT16_END; +-put16_12_920: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +-put16_12_021: _put_triple_s(dst, (u_int32_t)sample << 8); goto PUT16_END; +-put16_12_029: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 8); goto PUT16_END; +-put16_12_120_20: _put_triple(dst, (u_int32_t)sample << 4); goto PUT16_END; +-put16_12_920_20: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +-put16_12_021_20: _put_triple_s(dst, (u_int32_t)sample << 4); goto PUT16_END; +-put16_12_029_20: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 4); goto PUT16_END; +-put16_12_120_18: _put_triple(dst, (u_int32_t)sample << 2); goto PUT16_END; +-put16_12_920_18: _put_triple(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; +-put16_12_021_18: _put_triple_s(dst, (u_int32_t)sample << 2); goto PUT16_END; +-put16_12_029_18: _put_triple_s(dst, (u_int32_t)(sample ^ 0x8000) << 2); goto PUT16_END; ++put16_12_0120: as_u32(dst) = sx24((uint32_t)sample << 8); goto PUT16_END; ++put16_12_0920: as_u32(dst) = sx24((uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; ++put16_12_0210: as_u32(dst) = sx24s((uint32_t)bswap_16(sample) << 8); goto PUT16_END; ++put16_12_0290: as_u32(dst) = sx24s((uint32_t)(bswap_16(sample) ^ 0x80) << 8); goto PUT16_END; ++put16_12_1200: as_u32(dst) = (uint32_t)sample << 16; goto PUT16_END; ++put16_12_9200: as_u32(dst) = (uint32_t)(sample ^ 0x8000) << 16; goto PUT16_END; ++put16_12_0021: as_u32(dst) = (uint32_t)bswap_16(sample); goto PUT16_END; ++put16_12_0029: as_u32(dst) = (uint32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; ++put16_12_120: _put_triple(dst, (uint32_t)sample << 8); goto PUT16_END; ++put16_12_920: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; ++put16_12_021: _put_triple_s(dst, (uint32_t)sample << 8); goto PUT16_END; ++put16_12_029: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 8); goto PUT16_END; ++put16_12_120_20: _put_triple(dst, (uint32_t)sample << 4); goto PUT16_END; ++put16_12_920_20: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; ++put16_12_021_20: _put_triple_s(dst, (uint32_t)sample << 4); goto PUT16_END; ++put16_12_029_20: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 4); goto PUT16_END; ++put16_12_120_18: _put_triple(dst, (uint32_t)sample << 2); goto PUT16_END; ++put16_12_920_18: _put_triple(dst, (uint32_t)(sample ^ 0x8000) << 2); goto PUT16_END; ++put16_12_021_18: _put_triple_s(dst, (uint32_t)sample << 2); goto PUT16_END; ++put16_12_029_18: _put_triple_s(dst, (uint32_t)(sample ^ 0x8000) << 2); goto PUT16_END; + } + #endif + +@@ -517,12 +517,12 @@ static void *const get32_labels[4 * 2 * 2 + 4 * 3] = { + + #ifdef GET32_END + while (0) { +-get32_1_1000: sample = (u_int32_t)as_u8c(src) << 24; goto GET32_END; +-get32_1_9000: sample = (u_int32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; +-get32_12_1200: sample = (u_int32_t)as_u16c(src) << 16; goto GET32_END; +-get32_12_9200: sample = (u_int32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; +-get32_12_2100: sample = (u_int32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; +-get32_12_A100: sample = (u_int32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto GET32_END; ++get32_1_1000: sample = (uint32_t)as_u8c(src) << 24; goto GET32_END; ++get32_1_9000: sample = (uint32_t)(as_u8c(src) ^ 0x80) << 24; goto GET32_END; ++get32_12_1200: sample = (uint32_t)as_u16c(src) << 16; goto GET32_END; ++get32_12_9200: sample = (uint32_t)(as_u16c(src) ^ 0x8000) << 16; goto GET32_END; ++get32_12_2100: sample = (uint32_t)bswap_16(as_u16c(src)) << 16; goto GET32_END; ++get32_12_A100: sample = (uint32_t)bswap_16(as_u16c(src) ^ 0x80) << 16; goto GET32_END; + get32_0123_1230: sample = as_u32c(src) << 8; goto GET32_END; + get32_0123_9230: sample = (as_u32c(src) << 8) ^ 0x80000000; goto GET32_END; + get32_1230_3210: sample = bswap_32(as_u32c(src) >> 8); goto GET32_END; +@@ -786,18 +786,18 @@ static inline void _norms(const void *src, void *dst, + s += (1U << (dst_wid - 1)); + switch (dst_wid) { + case 8: +- *(u_int8_t*)dst = s; ++ *(uint8_t*)dst = s; + break; + case 16: + if (dst_end) + s = bswap_16(s); +- *(u_int16_t*)dst = s; ++ *(uint16_t*)dst = s; + break; + case 24: + case 32: + if (dst_end) + s = bswap_32(s); +- *(u_int32_t*)dst = s; ++ *(uint32_t*)dst = s; + break; + } + return; +@@ -806,27 +806,27 @@ static inline void _norms(const void *src, void *dst, + switch (dst_wid) { + case 8: + if (dst_sign) +- *(u_int8_t*)dst = 0x80; ++ *(uint8_t*)dst = 0x80; + else +- *(u_int8_t*)dst = 0; ++ *(uint8_t*)dst = 0; + break; + case 16: + if (dst_sign) +- *(u_int16_t*)dst = dst_end ? 0x0080 : 0x8000; ++ *(uint16_t*)dst = dst_end ? 0x0080 : 0x8000; + else +- *(u_int16_t*)dst = 0; ++ *(uint16_t*)dst = 0; + break; + case 24: + if (dst_sign) +- *(u_int32_t*)dst = dst_end ? 0x00008000 : 0x00800000; ++ *(uint32_t*)dst = dst_end ? 0x00008000 : 0x00800000; + else +- *(u_int32_t*)dst = 0; ++ *(uint32_t*)dst = 0; + break; + case 32: + if (dst_sign) +- *(u_int32_t*)dst = dst_end ? 0x00000080 : 0x80000000; ++ *(uint32_t*)dst = dst_end ? 0x00000080 : 0x80000000; + else +- *(u_int32_t*)dst = 0; ++ *(uint32_t*)dst = 0; + break; + default: + assert(0); +@@ -838,27 +838,27 @@ static inline void _norms(const void *src, void *dst, + switch (dst_wid) { + case 8: + if (dst_sign) +- *(u_int8_t*)dst = 0x7f; ++ *(uint8_t*)dst = 0x7f; + else +- *(u_int8_t*)dst = 0xff; ++ *(uint8_t*)dst = 0xff; + break; + case 16: + if (dst_sign) +- *(u_int16_t*)dst = dst_end ? 0xff7f : 0x7fff; ++ *(uint16_t*)dst = dst_end ? 0xff7f : 0x7fff; + else +- *(u_int16_t*)dst = 0; ++ *(uint16_t*)dst = 0; + break; + case 24: + if (dst_sign) +- *(u_int32_t*)dst = dst_end ? 0xffff7f00 : 0x007fffff; ++ *(uint32_t*)dst = dst_end ? 0xffff7f00 : 0x007fffff; + else +- *(u_int32_t*)dst = 0; ++ *(uint32_t*)dst = 0; + break; + case 32: + if (dst_sign) +- *(u_int32_t*)dst = dst_end ? 0xffffff7f : 0x7fffffff; ++ *(uint32_t*)dst = dst_end ? 0xffffff7f : 0x7fffffff; + else +- *(u_int32_t*)dst = 0; ++ *(uint32_t*)dst = 0; + break; + default: + assert(0); +-- +2.13.5 + + +From cb34cee0d8da2fb131986d5782ddf5cec985c532 Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Fri, 14 Jul 2017 18:47:05 +0200 +Subject: [PATCH 28/39] snd_user_file: avoid use wordexp + +As suggested in POSIX[1], wordexp might execute the shell. If the libc +implementation does so, it will break the firefox sandbox which does +not allow exec. This happened on Alpine Linux with musl libc[2]. + +Since we cannot guarantee that the system wordexp implementation does +not execute shell, we cannot really use it, and need to implement the +~/ expansion ourselves. + +We provide a configure option --with-wordexp for users that still may +need it, but we leave this off by default because wordexp is a large +attack vector and it is better to avoid it. + +[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html#tag_16_684_08 +[2]: http://bugs.alpinelinux.org/issues/7454#note-2 + +Signed-off-by: Natanael Copa +Signed-off-by: Takashi Iwai +--- + configure.ac | 19 ++++++++++++++++- + src/userfile.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 75 insertions(+), 9 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 26e5d125..fbcfa829 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -303,8 +303,25 @@ fi + + AC_SUBST(ALSA_DEPLIBS) + ++dnl Check for use of wordexp... ++AC_MSG_CHECKING(for use of wordexp) ++AC_ARG_WITH(wordexp, ++ AS_HELP_STRING([--with-wordexp], ++ [Use wordexp when expanding configs (default = no)]), ++ [case "$withval" in ++ y|yes) wordexp=yes ;; ++ *) wordexp=no ;; ++ esac],) ++if test "$wordexp" = "yes" ; then ++ AC_DEFINE(HAVE_WORDEXP, "1", [Enable use of wordexp]) ++ AC_MSG_RESULT(yes) ++ AC_CHECK_HEADER([wordexp.h],[], [AC_MSG_ERROR([Couldn't find wordexp.h])]) ++else ++ AC_MSG_RESULT(no) ++fi ++ + dnl Check for headers +-AC_CHECK_HEADERS([wordexp.h endian.h sys/endian.h sys/shm.h]) ++AC_CHECK_HEADERS([endian.h sys/endian.h sys/shm.h]) + + dnl Check for resmgr support... + AC_MSG_CHECKING(for resmgr support) +diff --git a/src/userfile.c b/src/userfile.c +index 72779da4..f2145470 100644 +--- a/src/userfile.c ++++ b/src/userfile.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + /** + * \brief Get the full file name +@@ -32,14 +33,13 @@ + * stores the first matchine one. The returned string is strdup'ed. + */ + +-#ifdef HAVE_WORDEXP_H ++#ifdef HAVE_WORDEXP + #include +-#include + int snd_user_file(const char *file, char **result) + { + wordexp_t we; + int err; +- ++ + assert(file && result); + err = wordexp(file, &we, WRDE_NOCMD); + switch (err) { +@@ -61,13 +61,62 @@ int snd_user_file(const char *file, char **result) + return 0; + } + +-#else /* !HAVE_WORDEXP_H */ +-/* just copy the string - would be nicer to expand by ourselves, though... */ ++#else /* !HAVE_WORDEX */ ++ ++#include ++#include ++#include ++#include ++#include ++ + int snd_user_file(const char *file, char **result) + { +- *result = strdup(file); +- if (! *result) ++ int err; ++ size_t len; ++ char *buf = NULL; ++ ++ assert(file && result); ++ *result = NULL; ++ ++ /* expand ~/ if needed */ ++ if (file[0] == '~' && file[1] == '/') { ++ const char *home = getenv("HOME"); ++ if (home == NULL) { ++ struct passwd pwent, *p = NULL; ++ uid_t id = getuid(); ++ size_t bufsize = 1024; ++ ++ buf = malloc(bufsize); ++ if (buf == NULL) ++ goto out; ++ ++ while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) { ++ char *newbuf; ++ bufsize += 1024; ++ if (bufsize < 1024) ++ break; ++ newbuf = realloc(buf, bufsize); ++ if (newbuf == NULL) ++ goto out; ++ buf = newbuf; ++ } ++ home = err ? "" : pwent.pw_dir; ++ } ++ len = strlen(home) + strlen(&file[2]) + 2; ++ *result = malloc(len); ++ if (*result) ++ snprintf(*result, len, "%s/%s", home, &file[2]); ++ } else { ++ *result = strdup(file); ++ } ++ ++out: ++ if (buf) ++ free(buf); ++ ++ if (*result == NULL) + return -ENOMEM; + return 0; + } +-#endif /* HAVE_WORDEXP_H */ ++ ++#endif /* HAVE_WORDEXP */ +-- +2.13.5 + + +From c01dc3fa4899a9b9948629c103c0bc435d4f1574 Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Thu, 10 Aug 2017 13:36:16 +0200 +Subject: [PATCH 29/39] conf/ucm: DB410c-HiFi: add CIC selection + +This patch adds CIC selection controls which have been added recently to +the kernel to select mic source. + +Without this patch user has to manually select the control to record +from DMIC or AMIC. + +Signed-off-by: Srinivas Kandagatla +Signed-off-by: Takashi Iwai +--- + src/conf/ucm/DB410c/HiFi | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/conf/ucm/DB410c/HiFi b/src/conf/ucm/DB410c/HiFi +index f9cbcf05..dcb7ac98 100644 +--- a/src/conf/ucm/DB410c/HiFi ++++ b/src/conf/ucm/DB410c/HiFi +@@ -108,6 +108,7 @@ SectionDevice."Handset" { + EnableSequence [ + cdev "hw:0" + cset "name='DEC1 MUX' ADC2" ++ cset "name='CIC1 MUX' AMIC" + cset "name='ADC2 Volume' 8" + cset "name='ADC2 MUX' INP2" + ] +@@ -130,6 +131,7 @@ SectionDevice."Primarymic" { + EnableSequence [ + cdev "hw:0" + cset "name='DEC1 MUX' ADC1" ++ cset "name='CIC1 MUX' AMIC" + cset "name='ADC1 Volume' 8" + ] + +@@ -150,6 +152,7 @@ SectionDevice."Secondarymic" { + EnableSequence [ + cdev "hw:0" + cset "name='DEC1 MUX' ADC2" ++ cset "name='CIC1 MUX' AMIC" + cset "name='ADC2 Volume' 8" + cset "name='ADC2 MUX' INP2" + ] +@@ -172,6 +175,7 @@ SectionDevice."DMIC" { + EnableSequence [ + cdev "hw:0" + cset "name='DEC1 MUX' DMIC1" ++ cset "name='CIC1 MUX' DMIC" + ] + + DisableSequence [ +-- +2.13.5 + + +From 97da58213a7f56850468fc74726f255a5739cb49 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Fri, 11 Aug 2017 23:24:03 +0200 +Subject: [PATCH 30/39] rawmidi: symbols: use rawmidi_virt only when available + +src/rawmidi/Makefile.am only brings rawmidi_virt.c into the build when +BUILD_SEQ is defined (i.e when --enable-seq is passed). However, +rawmidi_symbols.c unconditionally refers to _snd_module_rawmidi_virt, +defined in rawmidi_virt.c. + +This causes a link failure when BUILD_SEQ is disabled. For example +when linking ffmpeg against alsa-lib: + +/home/thomas/projets/buildroot/output/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib/libasound.a(pcm_dmix.o): In function `snd_pcm_dmix_sync_ptr': +pcm_dmix.c:(.text+0x83c): warning: +/home/thomas/projets/buildroot/output/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib/libasound.a(rawmidi_symbols.o):(.data+0x4): undefined reference to `_snd_module_rawmidi_virt' +collect2: error: ld returned 1 exit status + +To fix this, we make sure that rawmidi_symbols.c only uses +_snd_module_rawmidi_virt when available. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Takashi Iwai +--- + src/rawmidi/rawmidi_symbols.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/rawmidi/rawmidi_symbols.c b/src/rawmidi/rawmidi_symbols.c +index cdc06d7f..64734334 100644 +--- a/src/rawmidi/rawmidi_symbols.c ++++ b/src/rawmidi/rawmidi_symbols.c +@@ -21,11 +21,15 @@ + #ifndef PIC + + extern const char *_snd_module_rawmidi_hw; ++#ifdef BUILD_SEQ + extern const char *_snd_module_rawmidi_virt; ++#endif + + static const char **snd_rawmidi_open_objects[] = { + &_snd_module_rawmidi_hw, ++#ifdef BUILD_SEQ + &_snd_module_rawmidi_virt ++#endif + }; + + void *snd_rawmidi_open_symbols(void) +-- +2.13.5 + + +From 80bd4ce1478efdc08189c82a74da183da591c0fb Mon Sep 17 00:00:00 2001 +From: Pierre-Louis Bossart +Date: Wed, 16 Aug 2017 11:08:48 -0500 +Subject: [PATCH 31/39] conf: HdmiLpeAudio: add support for 3 devices + +The LPE Audio mode on BYT/CHT supports up to 3 devices, and also supports +IEC61937 passthrough. Add missing alsa-lib configurations so that +apps can use the usual -D'hdmi:CARD=X,DEV=Y,AES0=0x[4|6]' syntax, e.g. + +aplay -D'hdmi:CARD=0,DEV=2,AES0=0x6' -c2 -r48000 -fs16_le +ac3_surround_test.spdif + +Tested on Zotac PI330 with Onkyo receiver + +Signed-off-by: Pierre-Louis Bossart +Signed-off-by: Takashi Iwai +--- + src/conf/cards/HdmiLpeAudio.conf | 77 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf +index dae71fac..9fa30da0 100644 +--- a/src/conf/cards/HdmiLpeAudio.conf ++++ b/src/conf/cards/HdmiLpeAudio.conf +@@ -56,6 +56,83 @@ HdmiLpeAudio.pcm.hdmi.0 { + { + interface PCM + name "IEC958 Playback Default" ++ device 0 ++ lock true ++ preserve true ++ value [ $AES0 $AES1 $AES2 $AES3 ] ++ } ++ ] ++ } ++} ++ ++HdmiLpeAudio.pcm.hdmi.1 { ++ @args [ CARD AES0 AES1 AES2 AES3 ] ++ @args.CARD { ++ type string ++ } ++ @args.AES0 { ++ type integer ++ } ++ @args.AES1 { ++ type integer ++ } ++ @args.AES2 { ++ type integer ++ } ++ @args.AES3 { ++ type integer ++ } ++ type hooks ++ slave.pcm { ++ type hw ++ card $CARD ++ device 1 ++ } ++ hooks.0 { ++ type ctl_elems ++ hook_args [ ++ { ++ interface PCM ++ name "IEC958 Playback Default" ++ device 1 ++ lock true ++ preserve true ++ value [ $AES0 $AES1 $AES2 $AES3 ] ++ } ++ ] ++ } ++} ++ ++HdmiLpeAudio.pcm.hdmi.2 { ++ @args [ CARD AES0 AES1 AES2 AES3 ] ++ @args.CARD { ++ type string ++ } ++ @args.AES0 { ++ type integer ++ } ++ @args.AES1 { ++ type integer ++ } ++ @args.AES2 { ++ type integer ++ } ++ @args.AES3 { ++ type integer ++ } ++ type hooks ++ slave.pcm { ++ type hw ++ card $CARD ++ device 2 ++ } ++ hooks.0 { ++ type ctl_elems ++ hook_args [ ++ { ++ interface PCM ++ name "IEC958 Playback Default" ++ device 2 + lock true + preserve true + value [ $AES0 $AES1 $AES2 $AES3 ] +-- +2.13.5 + + +From 52826d4655fac9fa86600d5238391eb2c8ca8092 Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Tue, 22 Aug 2017 10:16:05 +0100 +Subject: [PATCH 32/39] topology: Fix private data for BEs + +Private data was not being added to BEs. Fix this. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/data.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/topology/data.c b/src/topology/data.c +index 5b83b9fc..f96ff9bb 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -50,7 +50,9 @@ struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem) + case SND_TPLG_TYPE_DAI: + priv = &elem->dai->priv; + break; +- ++ case SND_TPLG_TYPE_BE: ++ priv = &elem->link->priv; ++ break; + default: + SNDERR("error: '%s': no support for private data for type %d\n", + elem->id, elem->type); +-- +2.13.5 + + +From 5efdabc1ab60f443f7183e50fea99510d0e3fe77 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Thu, 24 Aug 2017 10:48:35 +0900 +Subject: [PATCH 33/39] test: apply optimization for v4.14 kernel about changes + for TLV data handling on user-defined element set + +At kernel v4.14, in initial state, elements on user-defined sets have +write-only flag. When applications write TLV data, then the elements +get readable flag and the TLV data is available. Originally TLV data +is shared by elements in the same set, thus events are generated for +all of elements in the set by the write operation. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + test/user-ctl-element-set.c | 84 +++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 73 insertions(+), 11 deletions(-) + +diff --git a/test/user-ctl-element-set.c b/test/user-ctl-element-set.c +index 8635c156..f3710732 100644 +--- a/test/user-ctl-element-set.c ++++ b/test/user-ctl-element-set.c +@@ -9,6 +9,7 @@ + + #include "../include/asoundlib.h" + #include ++#include + + struct elem_set_trial { + snd_ctl_t *handle; +@@ -28,6 +29,8 @@ struct elem_set_trial { + snd_ctl_elem_value_t *elem_data); + int (*allocate_elem_set_tlv)(struct elem_set_trial *trial, + unsigned int **tlv); ++ ++ bool tlv_readable; + }; + + struct chmap_entry { +@@ -420,9 +423,9 @@ static int check_event(struct elem_set_trial *trial, unsigned int mask, + continue; + /* + * I expect each event is generated separately to the same +- * element. ++ * element or several events are generated at once. + */ +- if (!(snd_ctl_event_elem_get_mask(event) & mask)) ++ if ((snd_ctl_event_elem_get_mask(event) & mask) != mask) + continue; + --expected_count; + } +@@ -561,6 +564,16 @@ static int check_elem_set_props(struct elem_set_trial *trial) + if (!snd_ctl_elem_info_is_locked(info)) + return -EIO; + ++ /* ++ * In initial state, any application can register TLV data for ++ * user-defined element set except for IEC 958 type, thus ++ * elements in any user-defined set should allow any write ++ * operation. ++ */ ++ if (trial->type != SND_CTL_ELEM_TYPE_IEC958 && ++ !snd_ctl_elem_info_is_tlv_writable(info)) ++ return -EIO; ++ + /* Check type-specific properties. */ + if (trial->check_elem_props != NULL) { + err = trial->check_elem_props(trial, info); +@@ -572,6 +585,25 @@ static int check_elem_set_props(struct elem_set_trial *trial) + err = snd_ctl_elem_unlock(trial->handle, id); + if (err < 0) + return err; ++ ++ /* ++ * Till kernel v4.14, ALSA control core allows elements in any ++ * user-defined set to have TLV_READ flag even if they have no ++ * TLV data in their initial state. In this case, any read ++ * operation for TLV data should return -ENXIO. ++ */ ++ if (snd_ctl_elem_info_is_tlv_readable(info)) { ++ unsigned int data[32]; ++ err = snd_ctl_elem_tlv_read(trial->handle, trial->id, ++ data, sizeof(data)); ++ if (err >= 0) ++ return -EIO; ++ if (err != -ENXIO) ++ return err; ++ ++ trial->tlv_readable = true; ++ } ++ + } + + return 0; +@@ -619,6 +651,8 @@ static int check_elems(struct elem_set_trial *trial) + static int check_tlv(struct elem_set_trial *trial) + { + unsigned int *tlv; ++ int mask; ++ unsigned int count; + unsigned int len; + unsigned int *curr; + int err; +@@ -644,6 +678,36 @@ static int check_tlv(struct elem_set_trial *trial) + if (err < 0) + goto end; + ++ /* ++ * Since kernel v4.14, any write operation to an element in user-defined ++ * set can change state of the other elements in the same set. In this ++ * case, any TLV data is firstly available after the operation. ++ */ ++ if (!trial->tlv_readable) { ++ mask = SND_CTL_EVENT_MASK_INFO | SND_CTL_EVENT_MASK_TLV; ++ count = trial->element_count; ++ } else { ++ mask = SND_CTL_EVENT_MASK_TLV; ++ count = 1; ++ } ++ err = check_event(trial, mask, count); ++ if (err < 0) ++ goto end; ++ if (!trial->tlv_readable) { ++ snd_ctl_elem_info_t *info; ++ snd_ctl_elem_info_alloca(&info); ++ ++ snd_ctl_elem_info_set_id(info, trial->id); ++ err = snd_ctl_elem_info(trial->handle, info); ++ if (err < 0) ++ return err; ++ if (!snd_ctl_elem_info_is_tlv_readable(info)) ++ return -EIO; ++ ++ /* Now TLV data is available for this element set. */ ++ trial->tlv_readable = true; ++ } ++ + err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len); + if (err < 0) + goto end; +@@ -690,6 +754,7 @@ int main(void) + trial.change_elem_members = change_bool_elem_members; + trial.allocate_elem_set_tlv = + allocate_bool_elem_set_tlv; ++ trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_INTEGER: + trial.element_count = 900; +@@ -703,6 +768,7 @@ int main(void) + trial.change_elem_members = change_int_elem_members; + trial.allocate_elem_set_tlv = + allocate_int_elem_set_tlv; ++ trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + trial.element_count = 900; +@@ -715,6 +781,7 @@ int main(void) + trial.check_elem_props = check_enum_elem_props; + trial.change_elem_members = change_enum_elem_members; + trial.allocate_elem_set_tlv = NULL; ++ trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_BYTES: + trial.element_count = 900; +@@ -728,6 +795,7 @@ int main(void) + trial.change_elem_members = change_bytes_elem_members; + trial.allocate_elem_set_tlv = + allocate_bytes_elem_set_tlv; ++ trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_IEC958: + trial.element_count = 1; +@@ -740,6 +808,7 @@ int main(void) + trial.check_elem_props = NULL; + trial.change_elem_members = change_iec958_elem_members; + trial.allocate_elem_set_tlv = NULL; ++ trial.tlv_readable = false; + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + default: +@@ -754,6 +823,7 @@ int main(void) + trial.change_elem_members = change_int64_elem_members; + trial.allocate_elem_set_tlv = + allocate_int64_elem_set_tlv; ++ trial.tlv_readable = false; + break; + } + +@@ -784,7 +854,7 @@ int main(void) + /* Check properties of each element in this element set. */ + err = check_elem_set_props(&trial); + if (err < 0) { +- printf("Fail to check propetries of each element with " ++ printf("Fail to check properties of each element with " + "%s type.\n", + snd_ctl_elem_type_name(trial.type)); + break; +@@ -822,14 +892,6 @@ int main(void) + snd_ctl_elem_type_name(trial.type)); + break; + } +- err = check_event(&trial, SND_CTL_EVENT_MASK_TLV, 1); +- if (err < 0) { +- printf("Fail to check an event to change TLV" +- "data of an an element set with %s " +- "type.\n", +- snd_ctl_elem_type_name(trial.type)); +- break; +- } + } + + /* Test an operation to remove elements in this element set. */ +-- +2.13.5 + + +From 8d6169514519a3f3246ad09dd1281e3a7d854d42 Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Tue, 12 Sep 2017 21:47:42 +0100 +Subject: [PATCH 34/39] topology: fix usage of SND_TPLG_INDEX_ALL when checking + routes + +Make sure SND_TPLG_INDEX_ALL is used correctly when checking routes so +that connecting routes of different indexes does not emit any warnings. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/dapm.c | 4 ++-- + src/topology/elem.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 66892a66..0ddbf965 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -279,7 +279,7 @@ int tplg_build_routes(snd_tplg_t *tplg) + + } + if (!tplg_elem_lookup(&tplg->widget_list, route->sink, +- SND_TPLG_TYPE_DAPM_WIDGET, elem->index)) { ++ SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { + SNDERR("warning: undefined sink widget/stream '%s'\n", + route->sink); + } +@@ -302,7 +302,7 @@ int tplg_build_routes(snd_tplg_t *tplg) + + } + if (!tplg_elem_lookup(&tplg->widget_list, route->source, +- SND_TPLG_TYPE_DAPM_WIDGET, elem->index)) { ++ SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) { + SNDERR("warning: Undefined source widget/stream '%s'\n", + route->source); + } +diff --git a/src/topology/elem.c b/src/topology/elem.c +index 89a4ac9f..9a7c7b75 100644 +--- a/src/topology/elem.c ++++ b/src/topology/elem.c +@@ -123,7 +123,7 @@ struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id, + return elem; + /* SND_TPLG_INDEX_ALL is the default value "0" and applicable + for all use cases */ +- if ((elem->index != SND_TPLG_INDEX_ALL) ++ if ((index != SND_TPLG_INDEX_ALL) + && (elem->index > index)) + break; + } +-- +2.13.5 + + +From 6a617cc719d553ad8eb96308b7f3b94f5a53d243 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Krause?= +Date: Wed, 13 Sep 2017 16:21:10 +0200 +Subject: [PATCH 35/39] pcm: softvol: add support for S24_LE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Tested with the Wolfson WM8524 DAC on a i.MX6UL board and the following +ALSA configuration file using the pcm test utility from alsa-lib: + +""" +$ cat /etc/asound.conf +pcm.!default { + type plug + slave.pcm "softvol" +} +pcm.softvol { + type softvol + slave { + pcm "hw:0" + } + control { + name "Master" + card 0 + } +} +ctl.!default { + type hw + card 0 +} +ctl.softvol { + type hw + card 0 +} + +$ pcm -D softvol -o S24_LE -c 2 -r 48000 +""" + +The data in the Synchronous Audio Interface (SAI) of the i.MX6UL is +aligned the following way: + +""" +31 30 29 28 | 27 26 25 24 | 23 22 21 20 | .. | 3 2 1 0 +## ## ## ## ## ## ## ## [ DATA[23:0] ] +""" + +Signed-off-by: Jörg Krause +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_softvol.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 53 insertions(+), 3 deletions(-) + +diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c +index 1fe5784d..68a35b56 100644 +--- a/src/pcm/pcm_softvol.c ++++ b/src/pcm/pcm_softvol.c +@@ -251,6 +251,44 @@ static inline short MULTI_DIV_short(short a, unsigned int b, int swap) + } \ + } \ + } while (0) ++ ++#define CONVERT_AREA_S24_LE() do { \ ++ unsigned int ch, fr; \ ++ int *src, *dst; \ ++ int tmp; \ ++ for (ch = 0; ch < channels; ch++) { \ ++ src_area = &src_areas[ch]; \ ++ dst_area = &dst_areas[ch]; \ ++ src = snd_pcm_channel_area_addr(src_area, src_offset); \ ++ dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ ++ src_step = snd_pcm_channel_area_step(src_area) \ ++ / sizeof(int); \ ++ dst_step = snd_pcm_channel_area_step(dst_area) \ ++ / sizeof(int); \ ++ GET_VOL_SCALE; \ ++ fr = frames; \ ++ if (! vol_scale) { \ ++ while (fr--) { \ ++ *dst = 0; \ ++ dst += dst_step; \ ++ } \ ++ } else if (vol_scale == 0xffff) { \ ++ while (fr--) { \ ++ *dst = *src; \ ++ src += dst_step; \ ++ dst += src_step; \ ++ } \ ++ } else { \ ++ while (fr--) { \ ++ tmp = *src << 8; \ ++ tmp = (signed int) tmp >> 8; \ ++ *dst = MULTI_DIV_24(tmp, vol_scale); \ ++ src += dst_step; \ ++ dst += src_step; \ ++ } \ ++ } \ ++ } \ ++} while (0) + + #define GET_VOL_SCALE \ + switch (ch) { \ +@@ -315,6 +353,10 @@ static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol, + CONVERT_AREA(int, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; ++ case SND_PCM_FORMAT_S24_LE: ++ /* 24bit samples */ ++ CONVERT_AREA_S24_LE(); ++ break; + case SND_PCM_FORMAT_S24_3LE: + CONVERT_AREA_S24_3LE(); + break; +@@ -366,6 +408,10 @@ static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol, + CONVERT_AREA(int, + !snd_pcm_format_cpu_endian(svol->sformat)); + break; ++ case SND_PCM_FORMAT_S24_LE: ++ /* 24bit samples */ ++ CONVERT_AREA_S24_LE(); ++ break; + case SND_PCM_FORMAT_S24_3LE: + CONVERT_AREA_S24_3LE(); + break; +@@ -422,6 +468,7 @@ static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm, + { + (1ULL << SND_PCM_FORMAT_S16_LE) | + (1ULL << SND_PCM_FORMAT_S16_BE) | ++ (1ULL << SND_PCM_FORMAT_S24_LE) | + (1ULL << SND_PCM_FORMAT_S32_LE) | + (1ULL << SND_PCM_FORMAT_S32_BE), + (1ULL << (SND_PCM_FORMAT_S24_3LE - 32)) +@@ -577,10 +624,11 @@ static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * param + if (slave->format != SND_PCM_FORMAT_S16_LE && + slave->format != SND_PCM_FORMAT_S16_BE && + slave->format != SND_PCM_FORMAT_S24_3LE && ++ slave->format != SND_PCM_FORMAT_S24_LE && + slave->format != SND_PCM_FORMAT_S32_LE && + slave->format != SND_PCM_FORMAT_S32_BE) { +- SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE " +- " or S32_BE"); ++ SNDERR("softvol supports only S16_LE, S16_BE, S24_LE, S24_3LE, " ++ "S32_LE or S32_BE"); + return -EINVAL; + } + svol->sformat = slave->format; +@@ -863,6 +911,7 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, + sformat != SND_PCM_FORMAT_S16_LE && + sformat != SND_PCM_FORMAT_S16_BE && + sformat != SND_PCM_FORMAT_S24_3LE && ++ sformat != SND_PCM_FORMAT_S24_LE && + sformat != SND_PCM_FORMAT_S32_LE && + sformat != SND_PCM_FORMAT_S32_BE) + return -EINVAL; +@@ -1082,9 +1131,10 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, + sformat != SND_PCM_FORMAT_S16_LE && + sformat != SND_PCM_FORMAT_S16_BE && + sformat != SND_PCM_FORMAT_S24_3LE && ++ sformat != SND_PCM_FORMAT_S24_LE && + sformat != SND_PCM_FORMAT_S32_LE && + sformat != SND_PCM_FORMAT_S32_BE) { +- SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format is supported"); ++ SNDERR("only S16_LE, S16_BE, S24_LE, S24_3LE, S32_LE or S32_BE format is supported"); + snd_config_delete(sconf); + return -EINVAL; + } +-- +2.13.5 + + +From baed295faafb076d380392fa938234a7ec426dfc Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Thu, 28 Sep 2017 15:46:15 +0200 +Subject: [PATCH 36/39] seq: fix snd_seq_set_queue_tempo() usage example in the + documentation + +snd_seq_set_queue_tempo() requires a queue id as the second argument, +fix the example in documentation to reflect that. + +Also add the queue id as an argument of the set_tempo() function, just +to keep the whole example compilable. + +Signed-off-by: Antonio Ospite +Signed-off-by: Takashi Iwai +--- + src/seq/seq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/seq/seq.c b/src/seq/seq.c +index d5ed1c6a..808c7915 100644 +--- a/src/seq/seq.c ++++ b/src/seq/seq.c +@@ -452,13 +452,13 @@ For setting these tempo parameters, use #snd_seq_queue_tempo_t record. + For example, to set the tempo of the queue q to + 48 PPQ, 60 BPM, + \code +-void set_tempo(snd_seq_t *handle) ++void set_tempo(snd_seq_t *handle, int queue) + { + snd_seq_queue_tempo_t *tempo; + snd_seq_queue_tempo_alloca(&tempo); + snd_seq_queue_tempo_set_tempo(tempo, 1000000); // 60 BPM + snd_seq_queue_tempo_set_ppq(tempo, 48); // 48 PPQ +- snd_seq_set_queue_tempo(handle, tempo); ++ snd_seq_set_queue_tempo(handle, queue, tempo); + } + \endcode + +-- +2.13.5 + + +From 8c0b17bca3d641dc86d35eb1b97fae5fe4080984 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Tue, 26 Sep 2017 16:44:49 +0200 +Subject: [PATCH 37/39] test/seq-decoder: enable timestamping for external + subscribers + +Events sent by external clients subscribed to the input port are not +timestamped. + +This inconsistent behavior may surprise newbies who look at seq-decoder as +a reference example. + +See the example below using "vkeybd --addr 128:0" to connect to seq-decoder, +the events sent by vkeybd are on a different queue with no timestamps: + + ... + EVENT>>> Type = 66, flags = 0x0, time = 0 ticks + Source = 0.1, dest = 128.0, queue = 253 + Event = Port Subscribed; 129:0 -> 128:0 + EVENT>>> Type = 66, flags = 0x1, time = 4.829712627 + Source = 0.1, dest = 128.0, queue = 0 + Event = Port Subscribed; 129:0 -> 128:0 + EVENT>>> Type = 10, flags = 0x0, time = 0 ticks + Source = 129.0, dest = 128.0, queue = 253 + Event = Controller; ch=0, param=0, value=0 + EVENT>>> Type = 11, flags = 0x0, time = 0 ticks + Source = 129.0, dest = 128.0, queue = 253 + Event = Program Change; ch=0, program=0 + ... + +After the change events are on the main queue and are timestamped: + + ... + EVENT>>> Type = 66, flags = 0x1, time = 4.280907223 + Source = 0.1, dest = 128.0, queue = 0 + Event = Port Subscribed; 129:0 -> 128:0 + EVENT>>> Type = 66, flags = 0x1, time = 4.280912063 + Source = 0.1, dest = 128.0, queue = 0 + Event = Port Subscribed; 129:0 -> 128:0 + EVENT>>> Type = 10, flags = 0x1, time = 4.280990702 + Source = 129.0, dest = 128.0, queue = 0 + Event = Controller; ch=0, param=0, value=0 + EVENT>>> Type = 11, flags = 0x1, time = 4.280994862 + Source = 129.0, dest = 128.0, queue = 0 + Event = Program Change; ch=0, program=0 + ... + +Signed-off-by: Antonio Ospite +Signed-off-by: Takashi Iwai +--- + test/seq-decoder.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/test/seq-decoder.c b/test/seq-decoder.c +index b110e98d..38755553 100644 +--- a/test/seq-decoder.c ++++ b/test/seq-decoder.c +@@ -283,6 +283,12 @@ void event_decoder(snd_seq_t *handle, int argc, char *argv[]) + snd_seq_port_info_set_name(pinfo, "Input"); + snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE); ++ ++ /* Enable timestamping for events sent by external subscribers. */ ++ snd_seq_port_info_set_timestamping(pinfo, 1); ++ snd_seq_port_info_set_timestamp_real(pinfo, 1); ++ snd_seq_port_info_set_timestamp_queue(pinfo, queue); ++ + if ((err = snd_seq_create_port(handle, pinfo)) < 0) { + fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); + return; +-- +2.13.5 + + +From 98d2c12ac2f8dc7e92790e927f472e26459d3852 Mon Sep 17 00:00:00 2001 +From: Timo Wischer +Date: Thu, 5 Oct 2017 16:25:23 +0200 +Subject: [PATCH 38/39] ctl: ext: Fail with error code if + snd_ctl_ext_callback::read_event() callback is not defined + +The snd_ctl_ext_callback::read_event() callback is only optional +if no poll descriptor was given via +snd_ctl_ext_t::poll_fd +or +snd_ctl_ext_callback::snd_ctl_ext_poll_descriptors(). + +If a poll descriptor is given the +snd_ctl_ext_callback::read_event() +callback has also to be defined +because there is no minigful default behavior. + +This callback will be called when ever the poll() on +the file descriptor indicates that there is an event pending. +Therefore returning a 0 which indicates that there is no event makes no +sense. + +Signed-off-by: Timo Wischer +Signed-off-by: Takashi Iwai +--- + src/control/control_ext.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/control/control_ext.c b/src/control/control_ext.c +index 56552fa1..d7de8e84 100644 +--- a/src/control/control_ext.c ++++ b/src/control/control_ext.c +@@ -415,8 +415,12 @@ static int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event) + { + snd_ctl_ext_t *ext = handle->private_data; + +- memset(event, 0, sizeof(*event)); +- return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); ++ if (ext->callback->read_event) { ++ memset(event, 0, sizeof(*event)); ++ return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); ++ } ++ ++ return -EINVAL; + } + + static int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle) +-- +2.13.5 + + +From 996dd33b5f0df06d0b1fdd8f43b7a212c26e2a27 Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen +Date: Wed, 4 Oct 2017 22:44:00 +0300 +Subject: [PATCH 39/39] conf: HdmiLpeAudio: remove the "front" pcm definition + +PulseAudio assumes that the "front" pcm device always refers to an +analog device, not HDMI. While that assumption is not really valid, the +reality is that without that assumption PulseAudio can't know whether +"front" and "hdmi" refer to a different or the same device. + +The HDMI LPE driver doesn't allow audio streaming while the HDMI cable +is unplugged, so PulseAudio has to know when it's plugged in and when +it's not. If both "front" and "hdmi" devices exist, PulseAudio will +notice that HDMI is unplugged, but it doesn't know that "front" refers +to the same device, and PulseAudio will try to use the "front" device +with bad consequences. The kernel driver's refusal to stream any audio +makes PulseAudio enter an infinite loop and then the kernel kills +PulseAudio, because it consumes too much CPU time in a realtime thread. + +While the looping in PulseAudio could probably be fixed, that wouldn't +change the fact that PulseAudio thinks that there is an analog device. I +believe it's best to avoid having the same device as both "front" and +"hdmi" in alsa-lib. + +I removed also the surround configuration includes. I don't think they +had any effect anyway, so I wonder why they were there in the first +place. + +BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100488 +Signed-off-by: Takashi Iwai +--- + src/conf/cards/HdmiLpeAudio.conf | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf +index 9fa30da0..a1e493da 100644 +--- a/src/conf/cards/HdmiLpeAudio.conf ++++ b/src/conf/cards/HdmiLpeAudio.conf +@@ -2,30 +2,6 @@ + # Configuration for the Intel HDMI/DP LPE audio + # + +- +- +-HdmiLpeAudio.pcm.front.0 { +- @args [ CARD ] +- @args.CARD { +- type string +- } +- type softvol +- slave.pcm { +- type hw +- card $CARD +- } +- control { +- name "PCM Playback Volume" +- card $CARD +- } +-} +- +- +- +- +- +- +- + + + HdmiLpeAudio.pcm.hdmi.0 { +-- +2.13.5 + +From 7f3ad37fd7e9327542be7f467ad337dd7398e2b7 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Sun, 22 Oct 2017 15:02:19 +0200 +Subject: [PATCH] topology: fix coverity issues + +--- + src/topology/ctl.c | 6 +++--- + src/topology/dapm.c | 7 ++++++- + src/topology/data.c | 7 +++---- + src/topology/elem.c | 4 +++- + 4 files changed, 15 insertions(+), 9 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index e73d9eb7..9dd88db6 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -130,7 +130,7 @@ static int tplg_build_mixer_control(snd_tplg_t *tplg, + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); +- if (ref->id == NULL || ref->elem) ++ if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_TLV) { +@@ -180,7 +180,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); +- if (ref->id == NULL || ref->elem) ++ if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_TEXT) { +@@ -216,7 +216,7 @@ static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem) + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); +- if (ref->id == NULL || ref->elem) ++ if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_DATA) { +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 0ddbf965..e5d473a8 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -428,7 +428,7 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, + snd_config_t *n; + int err; + const char *graph_id, *val = NULL; +- int index; ++ int index = -1; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("error: compound is expected for dapm graph definition\n"); +@@ -452,6 +452,11 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, + } + + if (strcmp(id, "lines") == 0) { ++ if (index < 0) { ++ SNDERR("error: failed to parse dapm graph %s, missing index\n", ++ graph_id); ++ return -EINVAL; ++ } + err = tplg_parse_routes(tplg, n, index); + if (err < 0) { + SNDERR("error: failed to parse dapm graph %s\n", +diff --git a/src/topology/data.c b/src/topology/data.c +index f96ff9bb..6b7c3f6c 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -132,7 +132,6 @@ err: + static void dump_priv_data(struct tplg_elem *elem) + { + struct snd_soc_tplg_private *priv = elem->data; +- unsigned char *p = (unsigned char *)priv->data; + unsigned int i, j = 0; + + tplg_dbg(" elem size = %d, priv data size = %d\n", +@@ -366,7 +365,7 @@ static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem) + + ref = list_entry(pos, struct tplg_ref, list); + +- if (!ref->id || ref->type != SND_TPLG_TYPE_TOKEN) ++ if (ref->type != SND_TPLG_TYPE_TOKEN) + continue; + + if (!ref->elem) { +@@ -390,7 +389,7 @@ static bool has_tuples(struct tplg_elem *elem) + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); +- if (ref->id && ref->type == SND_TPLG_TYPE_TUPLE) ++ if (ref->type == SND_TPLG_TYPE_TUPLE) + return true; + } + +@@ -504,7 +503,7 @@ static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem) + + ref = list_entry(pos, struct tplg_ref, list); + +- if (!ref->id || ref->type != SND_TPLG_TYPE_TUPLE) ++ if (ref->type != SND_TPLG_TYPE_TUPLE) + continue; + + tplg_dbg("tuples '%s' used by data '%s'\n", ref->id, elem->id); +diff --git a/src/topology/elem.c b/src/topology/elem.c +index 9a7c7b75..16ad4423 100644 +--- a/src/topology/elem.c ++++ b/src/topology/elem.c +@@ -178,8 +178,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, + if (snd_config_get_id(n, &id)) + continue; + if (strcmp(id, "index") == 0) { +- if (snd_config_get_string(n, &val) < 0) ++ if (snd_config_get_string(n, &val) < 0) { ++ free(elem); + return NULL; ++ } + elem->index = atoi(val); + } + } +-- +2.13.5 + diff --git a/SPECS/alsa-lib.spec b/SPECS/alsa-lib.spec index babec3f..065b8a6 100644 --- a/SPECS/alsa-lib.spec +++ b/SPECS/alsa-lib.spec @@ -4,8 +4,8 @@ Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib -Version: 1.1.3 -Release: 3%{?prever_dot}%{?dist} +Version: 1.1.4.1 +Release: 2%{?prever_dot}%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.alsa-project.org/ @@ -14,7 +14,7 @@ Source: ftp://ftp.alsa-project.org/pub/lib/%{name}-%{version}%{?prever}%{?post Source10: asound.conf Source11: modprobe-dist-alsa.conf Source12: modprobe-dist-oss.conf -Patch0: alsa-lib-1.1.3-post.patch +Patch0: alsa-lib-1.1.4.1-post.patch Patch1: alsa-lib-1.1.0-config.patch BuildRequires: doxygen @@ -114,6 +114,10 @@ find %{buildroot} -name '*.la' -delete %{_datadir}/aclocal/alsa.m4 %changelog +* Sun Oct 22 2017 Jaroslav Kysela - 1.1.4.1-2 +- Updated to 1.1.4.1 +- Resolves: rhbz#1485645 + * Wed Mar 1 2017 Jaroslav Kysela - 1.1.3-3 - Updated to 1.1.3 - Resolves: rhbz#1399508