diff --git a/0001-ucm-Add-ATTRIBUTE_UNUSED-for-unused-parameters-of-ex.patch b/0001-ucm-Add-ATTRIBUTE_UNUSED-for-unused-parameters-of-ex.patch new file mode 100644 index 0000000..5b2963c --- /dev/null +++ b/0001-ucm-Add-ATTRIBUTE_UNUSED-for-unused-parameters-of-ex.patch @@ -0,0 +1,43 @@ +From 6ad2a9763d9aaab30c0470d039877b1bb61dda3b Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Tue, 27 Dec 2016 18:08:58 +0800 +Subject: [PATCH 01/43] 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(-) + +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -486,9 +486,9 @@ static int execute_sequence(snd_use_case + */ + 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; diff --git a/0002-ucm-parser-needs-limits.h.patch b/0002-ucm-parser-needs-limits.h.patch new file mode 100644 index 0000000..6db9e09 --- /dev/null +++ b/0002-ucm-parser-needs-limits.h.patch @@ -0,0 +1,24 @@ +From 9ed4075f05a4242f32331f7f2c365767970f5003 Mon Sep 17 00:00:00 2001 +From: Gustavo Zacarias +Date: Wed, 21 Dec 2016 19:46:34 -0300 +Subject: [PATCH 02/43] 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(+) + +--- 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" diff --git a/0003-pcm-direct-allow-users-to-configure-different-period.patch b/0003-pcm-direct-allow-users-to-configure-different-period.patch new file mode 100644 index 0000000..0af8c42 --- /dev/null +++ b/0003-pcm-direct-allow-users-to-configure-different-period.patch @@ -0,0 +1,237 @@ +From 0a61c796810fcec8b386e5311e871b1744b45a67 Mon Sep 17 00:00:00 2001 +From: Joshua Frkuska +Date: Fri, 30 Dec 2016 11:56:15 +0530 +Subject: [PATCH 03/43] 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(-) + +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -660,6 +660,29 @@ static int hw_param_interval_refine_minm + 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 * + &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 * + } 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 * + 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(sn + + 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_ + 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_c + 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_c + 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; + } +--- 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; + }; +--- 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, + 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: +--- 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 + 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: +--- 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 + 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: diff --git a/0004-pcm-dshare-enable-silence.patch b/0004-pcm-dshare-enable-silence.patch new file mode 100644 index 0000000..dca81f2 --- /dev/null +++ b/0004-pcm-dshare-enable-silence.patch @@ -0,0 +1,34 @@ +From 8eeee1ab7d7db3110b7b3bb31cfb989304dced94 Mon Sep 17 00:00:00 2001 +From: Alexander Jahn +Date: Fri, 30 Dec 2016 11:59:11 +0530 +Subject: [PATCH 04/43] 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(-) + +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -1161,7 +1161,8 @@ int snd_pcm_direct_initialize_slave(snd_ + 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); diff --git a/0005-pcm-rate-fix-the-hw_ptr-update-until-the-boundary-av.patch b/0005-pcm-rate-fix-the-hw_ptr-update-until-the-boundary-av.patch new file mode 100644 index 0000000..6761b36 --- /dev/null +++ b/0005-pcm-rate-fix-the-hw_ptr-update-until-the-boundary-av.patch @@ -0,0 +1,92 @@ +From 7570e5d77514d8d8af387da04a010fa2ccaf543c Mon Sep 17 00:00:00 2001 +From: "mahendran.k" +Date: Fri, 30 Dec 2016 11:59:27 +0530 +Subject: [PATCH 05/43] 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(-) + +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -50,7 +50,7 @@ typedef struct _snd_pcm_rate snd_pcm_rat + + 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_hwp + { + 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_ + 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 + 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; diff --git a/0006-plugin-dynamically-update-avail_min-on-slave.patch b/0006-plugin-dynamically-update-avail_min-on-slave.patch new file mode 100644 index 0000000..0b08929 --- /dev/null +++ b/0006-plugin-dynamically-update-avail_min-on-slave.patch @@ -0,0 +1,101 @@ +From 88e4ae27bb4e47029ed57cc8e02fb1ddf2157fd9 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Mon, 19 Dec 2016 12:37:50 +0900 +Subject: [PATCH 06/43] 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(-) + +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -535,6 +535,68 @@ static int snd_pcm_plugin_status(snd_pcm + 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_ + .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 diff --git a/0007-rate-dynamic-update-avail_min-on-slave.patch b/0007-rate-dynamic-update-avail_min-on-slave.patch new file mode 100644 index 0000000..b72c4fd --- /dev/null +++ b/0007-rate-dynamic-update-avail_min-on-slave.patch @@ -0,0 +1,57 @@ +From ff1f669df4b05da3c44dc4a79ce00233fe9de9b7 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Mon, 19 Dec 2016 12:37:51 +0900 +Subject: [PATCH 07/43] 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(-) + +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -535,8 +535,8 @@ static int snd_pcm_plugin_status(snd_pcm + 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 && +--- 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; + +--- 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_ + .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 = { diff --git a/0008-topology-fix-unused-const-variable-warning.patch b/0008-topology-fix-unused-const-variable-warning.patch new file mode 100644 index 0000000..72bf39e --- /dev/null +++ b/0008-topology-fix-unused-const-variable-warning.patch @@ -0,0 +1,42 @@ +From 6f7eaf92e7de73eb32bd97bad83a14fcb0f408f7 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Wed, 30 Nov 2016 00:44:32 +0900 +Subject: [PATCH 08/43] 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(-) + +--- 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; diff --git a/0009-seq-improve-documentation-about-new-get-pid-card-fun.patch b/0009-seq-improve-documentation-about-new-get-pid-card-fun.patch new file mode 100644 index 0000000..8f8d7c7 --- /dev/null +++ b/0009-seq-improve-documentation-about-new-get-pid-card-fun.patch @@ -0,0 +1,77 @@ +From 1eddf1f918845d1e6cbcac5516319b20cad80f2f Mon Sep 17 00:00:00 2001 +From: Adam Goode +Date: Tue, 3 Jan 2017 08:33:42 -0500 +Subject: [PATCH 09/43] 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(-) + +--- a/src/seq/seq.c ++++ b/src/seq/seq.c +@@ -1530,7 +1530,25 @@ int snd_seq_client_info_get_error_bounce + * \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 s + * \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) + { diff --git a/0010-pcm-direct-returning-semop-error-code-for-semaphore-.patch b/0010-pcm-direct-returning-semop-error-code-for-semaphore-.patch new file mode 100644 index 0000000..cea9e1a --- /dev/null +++ b/0010-pcm-direct-returning-semop-error-code-for-semaphore-.patch @@ -0,0 +1,38 @@ +From 3f0dc404f16af58d20b4489b0daafcf87555dfb7 Mon Sep 17 00:00:00 2001 +From: Mounesh Sutar +Date: Tue, 10 Jan 2017 12:03:17 +0530 +Subject: [PATCH 10/43] 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(-) + +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -263,7 +263,10 @@ static inline int snd_pcm_direct_semapho + { + 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_semapho + { + 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; + } + diff --git a/0011-pcm-direct-Fix-for-sync-issue-on-xrun-recover.patch b/0011-pcm-direct-Fix-for-sync-issue-on-xrun-recover.patch new file mode 100644 index 0000000..3dc1522 --- /dev/null +++ b/0011-pcm-direct-Fix-for-sync-issue-on-xrun-recover.patch @@ -0,0 +1,370 @@ +From 1a9bd0f0448106b917ae7f7bedccfcbf6ce84802 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:03:36 +0530 +Subject: [PATCH 11/43] 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(-) + +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -550,6 +550,101 @@ int snd_pcm_direct_timer_stop(snd_pcm_di + 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_ + } + 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 + 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) { +--- 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_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); + +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -434,15 +434,21 @@ static int snd_pcm_dmix_sync_ptr0(snd_pc + 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_mm + + 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_mm + 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_mm + 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); + } + +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -162,7 +162,7 @@ static int snd_pcm_dshare_sync_ptr0(snd_ + 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_ + 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_ + + 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_ + 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_ + 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); + } + +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -132,14 +132,21 @@ static int snd_pcm_dsnoop_sync_ptr(snd_p + 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_ + + 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) diff --git a/0012-pcm-direct-check-state-before-enter-poll-on-timer.patch b/0012-pcm-direct-check-state-before-enter-poll-on-timer.patch new file mode 100644 index 0000000..b75fc32 --- /dev/null +++ b/0012-pcm-direct-check-state-before-enter-poll-on-timer.patch @@ -0,0 +1,184 @@ +From 789ee39727a12d6573b4d79e9cd7a375e6b8b005 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:03:54 +0530 +Subject: [PATCH 12/43] 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(-) + +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -645,6 +645,46 @@ int snd_pcm_direct_client_chk_xrun(snd_p + 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; +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -307,6 +307,8 @@ int snd_pcm_direct_parse_bindings(snd_pc + 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); +--- 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 + 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_ + .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, + }; +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -255,17 +255,22 @@ static int snd_pcm_dshare_status(snd_pcm + 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_ + .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, + }; +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -208,17 +208,22 @@ static int snd_pcm_dsnoop_status(snd_pcm + 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_ + .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, + }; diff --git a/0013-pcm-direct-don-t-return-bogus-buffer-levels-in-xrun-.patch b/0013-pcm-direct-don-t-return-bogus-buffer-levels-in-xrun-.patch new file mode 100644 index 0000000..6995109 --- /dev/null +++ b/0013-pcm-direct-don-t-return-bogus-buffer-levels-in-xrun-.patch @@ -0,0 +1,51 @@ +From 79a358ae26f74ed9b92b2190d4725325edf0c787 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:04:09 +0530 +Subject: [PATCH 13/43] 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(+) + +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -882,6 +882,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_av + 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); + } + +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -570,6 +570,9 @@ static snd_pcm_sframes_t snd_pcm_dshare_ + 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); + } + +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -454,6 +454,9 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_ + if (err < 0) + return err; + } ++ if (dsnoop->state == SND_PCM_STATE_XRUN) ++ return -EPIPE; ++ + return snd_pcm_mmap_capture_avail(pcm); + } + diff --git a/0014-conf-ucm-broxton-add-broxton-rt298-conf-files.patch b/0014-conf-ucm-broxton-add-broxton-rt298-conf-files.patch new file mode 100644 index 0000000..54a9a0a --- /dev/null +++ b/0014-conf-ucm-broxton-add-broxton-rt298-conf-files.patch @@ -0,0 +1,284 @@ +From 360c976aaa051809c34cb412ffa52380baeaabee Mon Sep 17 00:00:00 2001 +From: Vinod Koul +Date: Thu, 12 Jan 2017 14:50:28 +0530 +Subject: [PATCH 14/43] 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 + +--- a/configure.ac ++++ b/configure.ac +@@ -684,6 +684,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pict + 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 +--- 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 +--- /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" ++ } ++} ++ +--- /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" ++ } ++} ++ +--- /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" ++ } ++} +--- /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) +--- /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" ++] diff --git a/0015-pcm-direct-Fix-deadlock-in-poll_descriptors.patch b/0015-pcm-direct-Fix-deadlock-in-poll_descriptors.patch new file mode 100644 index 0000000..9eb42d9 --- /dev/null +++ b/0015-pcm-direct-Fix-deadlock-in-poll_descriptors.patch @@ -0,0 +1,32 @@ +From 24e63b75275e9c923c336b8dba3919b980e8f234 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 16 Jan 2017 16:21:52 +0100 +Subject: [PATCH 15/43] 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(-) + +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -676,7 +676,8 @@ int snd_pcm_direct_poll_descriptors(snd_ + } + + /* 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: diff --git a/0016-ucm-Assure-the-user-input-card-name-not-to-exceed-ma.patch b/0016-ucm-Assure-the-user-input-card-name-not-to-exceed-ma.patch new file mode 100644 index 0000000..4130995 --- /dev/null +++ b/0016-ucm-Assure-the-user-input-card-name-not-to-exceed-ma.patch @@ -0,0 +1,43 @@ +From 2b9b3f013467765219c8ab8a50943d3c7db68f75 Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:52:35 +0800 +Subject: [PATCH 16/43] 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(+) + +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -1335,6 +1335,12 @@ static int load_master_config(const char + 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); +--- 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 diff --git a/0017-ucm-Load-device-specific-configuration-file-based-on.patch b/0017-ucm-Load-device-specific-configuration-file-based-on.patch new file mode 100644 index 0000000..cd496ae --- /dev/null +++ b/0017-ucm-Load-device-specific-configuration-file-based-on.patch @@ -0,0 +1,177 @@ +From 4b9297e65f541f1a6c1b4a036f66936b9cafe030 Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:53:35 +0800 +Subject: [PATCH 17/43] 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(-) + +--- 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_cas + 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 + 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) +--- 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 */ diff --git a/0018-ucm-Add-command-get-_file-to-get-the-config-file-nam.patch b/0018-ucm-Add-command-get-_file-to-get-the-config-file-nam.patch new file mode 100644 index 0000000..9cf8b04 --- /dev/null +++ b/0018-ucm-Add-command-get-_file-to-get-the-config-file-nam.patch @@ -0,0 +1,51 @@ +From e93d93a8cd37f94f119aba72ca05d7f92b648bcc Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:53:42 +0800 +Subject: [PATCH 18/43] 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(+) + +--- a/include/use-case.h ++++ b/include/use-case.h +@@ -230,6 +230,7 @@ int snd_use_case_get_list(snd_use_case_m + * 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} +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -1528,6 +1528,20 @@ int snd_use_case_get(snd_use_case_mgr_t + 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; diff --git a/0019-topology-Fix-incorrect-license-in-source-comments.patch b/0019-topology-Fix-incorrect-license-in-source-comments.patch new file mode 100644 index 0000000..d1906a9 --- /dev/null +++ b/0019-topology-Fix-incorrect-license-in-source-comments.patch @@ -0,0 +1,278 @@ +From ec40aafa4374f2388876702513c4b3eee2e2235f Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Tue, 24 Jan 2017 14:59:08 +0000 +Subject: [PATCH 19/43] 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 | 15 ++++++++------- + src/topology/channel.c | 15 ++++++++------- + src/topology/ctl.c | 15 ++++++++------- + src/topology/dapm.c | 15 ++++++++------- + src/topology/data.c | 15 ++++++++------- + src/topology/elem.c | 15 ++++++++------- + src/topology/ops.c | 15 ++++++++------- + src/topology/parser.c | 15 ++++++++------- + src/topology/pcm.c | 15 ++++++++------- + src/topology/text.c | 15 ++++++++------- + 10 files changed, 80 insertions(+), 70 deletions(-) + +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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 +--- 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 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 +- General Public License for more details. ++ 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/0020-conf-cards-add-support-for-pistachio-card.patch b/0020-conf-cards-add-support-for-pistachio-card.patch new file mode 100644 index 0000000..0a3bc9a --- /dev/null +++ b/0020-conf-cards-add-support-for-pistachio-card.patch @@ -0,0 +1,100 @@ +From 4dfa8f08fb834f7b087f35f9ba1746cd0c989d02 Mon Sep 17 00:00:00 2001 +From: Manohar Narkhede +Date: Wed, 25 Jan 2017 22:14:15 +0100 +Subject: [PATCH 20/43] 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 + +--- 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 \ +--- 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 + + + +--- /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 ++ diff --git a/0021-pcm-multi-Drop-the-fixed-slave_map-in-snd_pcm_multi_.patch b/0021-pcm-multi-Drop-the-fixed-slave_map-in-snd_pcm_multi_.patch new file mode 100644 index 0000000..87c9dab --- /dev/null +++ b/0021-pcm-multi-Drop-the-fixed-slave_map-in-snd_pcm_multi_.patch @@ -0,0 +1,44 @@ +From e1143dd9ba350eb19d13d4e298eeb55179712a1e Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 27 Jan 2017 12:01:51 +0100 +Subject: [PATCH 21/43] 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(-) + +--- 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, + 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, + 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; + diff --git a/0022-conf-Add-card-config-for-Intel-HDMI-DP-LPE-audio.patch b/0022-conf-Add-card-config-for-Intel-HDMI-DP-LPE-audio.patch new file mode 100644 index 0000000..6d8df98 --- /dev/null +++ b/0022-conf-Add-card-config-for-Intel-HDMI-DP-LPE-audio.patch @@ -0,0 +1,115 @@ +From 53dc36f1f465e2a1f9ed37906a7f16a438f941e4 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 7 Feb 2017 14:25:17 +0100 +Subject: [PATCH 22/43] 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 + +--- /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 ] ++ } ++ ] ++ } ++} +--- 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 \ diff --git a/0023-pcm-Avoid-lock-for-snd_pcm_nonblock.patch b/0023-pcm-Avoid-lock-for-snd_pcm_nonblock.patch new file mode 100644 index 0000000..f001385 --- /dev/null +++ b/0023-pcm-Avoid-lock-for-snd_pcm_nonblock.patch @@ -0,0 +1,43 @@ +From b5a2c06f6c5d69fc71ef648af95a044ee1dc25d0 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 9 Feb 2017 17:23:22 +0100 +Subject: [PATCH 23/43] 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(-) + +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -759,7 +759,10 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int + 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 + pcm->mode &= ~SND_PCM_NONBLOCK; + } + unlock: +- __snd_pcm_unlock(pcm); ++ /* __snd_pcm_unlock(pcm); */ /* FIXME: see above */ + return err; + } + diff --git a/0024-pcm-Disable-locking-in-async-mode.patch b/0024-pcm-Disable-locking-in-async-mode.patch new file mode 100644 index 0000000..91e5c0a --- /dev/null +++ b/0024-pcm-Disable-locking-in-async-mode.patch @@ -0,0 +1,41 @@ +From e31a3273df6eb619e35d10bf6a0fc0fded91d559 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 9 Feb 2017 17:29:21 +0100 +Subject: [PATCH 24/43] 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(-) + +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -799,6 +799,8 @@ int snd_pcm_async(snd_pcm_t *pcm, int si + 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_pc + * 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 */ + diff --git a/0025-pcm-dmix-Allow-disabling-x86-optimizations.patch b/0025-pcm-dmix-Allow-disabling-x86-optimizations.patch new file mode 100644 index 0000000..29bf7a3 --- /dev/null +++ b/0025-pcm-dmix-Allow-disabling-x86-optimizations.patch @@ -0,0 +1,152 @@ +From 22eca6468b4aea47c783770ec0739d1e13bf3bfc Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 10 Feb 2017 12:16:12 +0100 +Subject: [PATCH 25/43] 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(+) + +--- 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 ] +--- 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 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -1861,6 +1861,7 @@ int snd_pcm_direct_parse_open_conf(snd_c + 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_c + 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; + } +--- 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; + }; +--- 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, + 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) { +--- 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 + { + 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; +--- 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 + { + 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; diff --git a/0026-pcm-dmix_rewind-corrupts-application-pointer-fix.patch b/0026-pcm-dmix_rewind-corrupts-application-pointer-fix.patch new file mode 100644 index 0000000..3db7493 --- /dev/null +++ b/0026-pcm-dmix_rewind-corrupts-application-pointer-fix.patch @@ -0,0 +1,92 @@ +From df7694d80cdd7d273b34ead6841b9f32f5991966 Mon Sep 17 00:00:00 2001 +From: Timo Wischer +Date: Fri, 17 Feb 2017 12:45:36 +0530 +Subject: [PATCH 26/43] 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(-) + +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -706,7 +706,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_re + { + 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_re + 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_re + 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_re + 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_re + 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) diff --git a/0027-pcm-direct-fix-race-on-clearing-timer-events.patch b/0027-pcm-direct-fix-race-on-clearing-timer-events.patch new file mode 100644 index 0000000..72fb43c --- /dev/null +++ b/0027-pcm-direct-fix-race-on-clearing-timer-events.patch @@ -0,0 +1,97 @@ +From 9219034301a3bf3d8de57ac5672bbc1c53f18049 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Fri, 17 Feb 2017 12:45:56 +0530 +Subject: [PATCH 27/43] 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(-) + +--- 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, + } + + /* 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(sn + 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_ + 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_ + 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)) { +--- 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); + diff --git a/0028-pcm-file-Enable-file-writing-for-capture-path.patch b/0028-pcm-file-Enable-file-writing-for-capture-path.patch new file mode 100644 index 0000000..508f1dd --- /dev/null +++ b/0028-pcm-file-Enable-file-writing-for-capture-path.patch @@ -0,0 +1,77 @@ +From fe65b00f337dd08f8c14d54b0ce6b516424d78e8 Mon Sep 17 00:00:00 2001 +From: Timo Wischer +Date: Fri, 17 Feb 2017 12:47:17 +0530 +Subject: [PATCH 28/43] 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(-) + +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -544,6 +544,7 @@ static snd_pcm_sframes_t snd_pcm_file_wr + 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_re + __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_re + 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_re + } + + 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_pc + 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); diff --git a/0029-pcm-status-dump-fix-timestamp-formatting.patch b/0029-pcm-status-dump-fix-timestamp-formatting.patch new file mode 100644 index 0000000..62dc2e8 --- /dev/null +++ b/0029-pcm-status-dump-fix-timestamp-formatting.patch @@ -0,0 +1,42 @@ +From a50496346f39e91ecd42cb09bc5c95321131be55 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Fri, 17 Feb 2017 12:47:36 +0530 +Subject: [PATCH 29/43] 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(-) + +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -2194,9 +2194,10 @@ int snd_pcm_status_dump(snd_pcm_status_t + 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); diff --git a/0030-pcm-extplug-refinement-of-masks-in-extplug.patch b/0030-pcm-extplug-refinement-of-masks-in-extplug.patch new file mode 100644 index 0000000..0684b19 --- /dev/null +++ b/0030-pcm-extplug-refinement-of-masks-in-extplug.patch @@ -0,0 +1,27 @@ +From fbb957138135e09ed9fd0180dcad549aad815465 Mon Sep 17 00:00:00 2001 +From: Awais Belal +Date: Fri, 17 Feb 2017 12:47:49 +0530 +Subject: [PATCH 30/43] 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(+) + +--- 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 + 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); diff --git a/0031-pcm-rate-Add-capability-to-pass-configuration-node-t.patch b/0031-pcm-rate-Add-capability-to-pass-configuration-node-t.patch new file mode 100644 index 0000000..31254de --- /dev/null +++ b/0031-pcm-rate-Add-capability-to-pass-configuration-node-t.patch @@ -0,0 +1,185 @@ +From 97be19cf6f44fc5084828114c53281dff6e365b4 Mon Sep 17 00:00:00 2001 +From: Alan Young +Date: Thu, 7 Apr 2016 09:15:04 +0100 +Subject: [PATCH 31/43] 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(-) + +--- 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 */ +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1258,26 +1258,48 @@ static const char *const default_rate_pl + "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 + } + #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, + 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 + diff --git a/0032-Drop-ppc64-specific-workaround-for-versioned-symbols.patch b/0032-Drop-ppc64-specific-workaround-for-versioned-symbols.patch new file mode 100644 index 0000000..64ac68c --- /dev/null +++ b/0032-Drop-ppc64-specific-workaround-for-versioned-symbols.patch @@ -0,0 +1,60 @@ +From 3bad0a21b4d13d8d10691f382c836897fa7a7cb9 Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Wed, 22 Feb 2017 16:45:00 -0300 +Subject: [PATCH 32/43] 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(-) + +--- 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 */ diff --git a/0033-pcm_plugin-unify-the-snd_pcm_mmap_begin-result-value.patch b/0033-pcm_plugin-unify-the-snd_pcm_mmap_begin-result-value.patch new file mode 100644 index 0000000..9cc41cf --- /dev/null +++ b/0033-pcm_plugin-unify-the-snd_pcm_mmap_begin-result-value.patch @@ -0,0 +1,68 @@ +From b0e4652881f883023d2b190cf3897b7494d8d0ed Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:25:24 +0100 +Subject: [PATCH 33/43] pcm_plugin: unify the snd_pcm_mmap_begin result value + checking + +--- + src/pcm/pcm_plugin.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -251,8 +251,12 @@ static snd_pcm_sframes_t snd_pcm_plugin_ + 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_ + 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 *pc + 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_ + 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, diff --git a/0034-always-handle-return-value-from-snd_config_get_id-co.patch b/0034-always-handle-return-value-from-snd_config_get_id-co.patch new file mode 100644 index 0000000..3da8e98 --- /dev/null +++ b/0034-always-handle-return-value-from-snd_config_get_id-co.patch @@ -0,0 +1,46 @@ +From 8a38461fac67f6542308063ba8e9887a1a2fa84e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:26:33 +0100 +Subject: [PATCH 34/43] 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(-) + +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1339,7 +1339,8 @@ static int is_string_array(const snd_con + 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, + 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); +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -653,8 +653,8 @@ static int parse_tuple_sets(snd_config_t + 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; + } + diff --git a/0035-pcm-file-plugin-handle-snd_pcm_mmap_begin-error-path.patch b/0035-pcm-file-plugin-handle-snd_pcm_mmap_begin-error-path.patch new file mode 100644 index 0000000..6fa7cb9 --- /dev/null +++ b/0035-pcm-file-plugin-handle-snd_pcm_mmap_begin-error-path.patch @@ -0,0 +1,31 @@ +From b96f6f47852aa145645fb8626d009ec532246e55 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:29:18 +0100 +Subject: [PATCH 35/43] 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(-) + +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -593,11 +593,13 @@ static snd_pcm_sframes_t snd_pcm_file_mm + 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; + } + diff --git a/0036-topology-coverity-remove-dead-code.patch b/0036-topology-coverity-remove-dead-code.patch new file mode 100644 index 0000000..372982f --- /dev/null +++ b/0036-topology-coverity-remove-dead-code.patch @@ -0,0 +1,83 @@ +From db0e1dcfc22fb2e408a12993cda2d604e0fb10f8 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:46:18 +0100 +Subject: [PATCH 36/43] 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(-) + +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -173,7 +173,7 @@ static int tplg_build_enum_control(snd_t + { + 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_t + SNDERR("error: cannot find '%s' referenced by" + " control '%s'\n", ref->id, elem->id); + return -EINVAL; +- } else if (err < 0) +- return err; ++ } + } + + return 0; +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -917,7 +917,7 @@ int tplg_build_manifest_data(snd_tplg_t + 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) { +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -79,8 +79,8 @@ static int build_pcm(snd_tplg_t *tplg, s + 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, s + 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 *tpl + + /* 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) diff --git a/0037-ucm-parser-fix-possible-string-overflow-in-uc_mgr_im.patch b/0037-ucm-parser-fix-possible-string-overflow-in-uc_mgr_im.patch new file mode 100644 index 0000000..3c05a9a --- /dev/null +++ b/0037-ucm-parser-fix-possible-string-overflow-in-uc_mgr_im.patch @@ -0,0 +1,22 @@ +From ad188bbf7813eab6f42dcdf617aa947107118857 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:53:26 +0100 +Subject: [PATCH 37/43] ucm parser: fix possible string overflow in + uc_mgr_import_master_config() + +--- + src/ucm/parser.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -1453,7 +1453,8 @@ int uc_mgr_import_master_config(snd_use_ + 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); diff --git a/0038-dmix-plugin-fix-drain-for-nonblock-mode.patch b/0038-dmix-plugin-fix-drain-for-nonblock-mode.patch new file mode 100644 index 0000000..c304170 --- /dev/null +++ b/0038-dmix-plugin-fix-drain-for-nonblock-mode.patch @@ -0,0 +1,68 @@ +From fdc898d41135b26772d0fffe07e9eb0de6597125 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 20 Mar 2017 08:34:33 +0100 +Subject: [PATCH 38/43] dmix plugin: fix drain for nonblock mode + +--- + src/pcm/pcm_dmix.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -628,7 +628,7 @@ static int __snd_pcm_dmix_drain(snd_pcm_ + { + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t stop_threshold; +- int err; ++ int err = 0; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: +@@ -639,8 +639,6 @@ static int __snd_pcm_dmix_drain(snd_pcm_ + + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; +- if (pcm->mode & SND_PCM_NONBLOCK) +- return -EAGAIN; + if (dmix->state == SND_PCM_STATE_PREPARED) { + if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) + snd_pcm_dmix_start(pcm); +@@ -663,23 +661,33 @@ static int __snd_pcm_dmix_drain(snd_pcm_ + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) { + snd_pcm_dmix_drop(pcm); +- return err; ++ goto done; + } + if (dmix->state == SND_PCM_STATE_DRAINING) { + snd_pcm_dmix_sync_area(pcm); +- snd_pcm_wait_nocheck(pcm, -1); +- snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ ++ if ((pcm->mode & SND_PCM_NONBLOCK) == 0) { ++ snd_pcm_wait_nocheck(pcm, -1); ++ snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ ++ } + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: +- return -ESTRPIPE; ++ err = -ESTRPIPE; ++ goto done; ++ case SND_PCM_STATE_DRAINING: ++ if (pcm->mode & SND_PCM_NONBLOCK) { ++ err = -EAGAIN; ++ goto done; ++ } ++ break; + default: + break; + } + } + } while (dmix->state == SND_PCM_STATE_DRAINING); ++done: + pcm->stop_threshold = stop_threshold; +- return 0; ++ return err; + } + + static int snd_pcm_dmix_drain(snd_pcm_t *pcm) diff --git a/0039-dmix-plugin-drain-quickfix-for-the-previous-patch.patch b/0039-dmix-plugin-drain-quickfix-for-the-previous-patch.patch new file mode 100644 index 0000000..fafb450 --- /dev/null +++ b/0039-dmix-plugin-drain-quickfix-for-the-previous-patch.patch @@ -0,0 +1,34 @@ +From e4377b16454f3b7b222613a571bf4244ebd28e56 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 20 Mar 2017 08:41:53 +0100 +Subject: [PATCH 39/43] dmix plugin: drain - quickfix for the previous patch + +--- + src/pcm/pcm_dmix.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -674,16 +674,16 @@ static int __snd_pcm_dmix_drain(snd_pcm_ + case SND_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto done; +- case SND_PCM_STATE_DRAINING: +- if (pcm->mode & SND_PCM_NONBLOCK) { +- err = -EAGAIN; +- goto done; +- } +- break; + default: + break; + } + } ++ if (pcm->mode & SND_PCM_NONBLOCK) { ++ if (dmix->state == SND_PCM_STATE_DRAINING) { ++ err = -EAGAIN; ++ goto done; ++ } ++ } + } while (dmix->state == SND_PCM_STATE_DRAINING); + done: + pcm->stop_threshold = stop_threshold; diff --git a/0040-rawmidi-virtual-fix-reading-into-a-small-buffer.patch b/0040-rawmidi-virtual-fix-reading-into-a-small-buffer.patch new file mode 100644 index 0000000..8b023fa --- /dev/null +++ b/0040-rawmidi-virtual-fix-reading-into-a-small-buffer.patch @@ -0,0 +1,28 @@ +From d71f294566e53c967a6a1e2d5c684499ec390d69 Mon Sep 17 00:00:00 2001 +From: Clemens Ladisch +Date: Sat, 18 Mar 2017 23:10:33 +0100 +Subject: [PATCH 40/43] rawmidi: virtual: fix reading into a small buffer + +In the special case for handling partial messages, the pointer +calculations were wrong, which would result in data corruption. + +Signed-off-by: Clemens Ladisch +Reviewd-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/rawmidi/rawmidi_virt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/src/rawmidi/rawmidi_virt.c ++++ b/src/rawmidi/rawmidi_virt.c +@@ -263,8 +263,8 @@ static ssize_t snd_rawmidi_virtual_read( + } + size1 = virt->in_buf_size - virt->in_buf_ofs; + if ((size_t)size1 > size) { +- virt->in_buf_ofs += size1 - size; +- memcpy(buffer, virt->in_buf_ptr, size); ++ memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size); ++ virt->in_buf_ofs += size; + result += size; + break; + } diff --git a/0041-conf-cards-add-VC4-HDMI-card.patch b/0041-conf-cards-add-VC4-HDMI-card.patch new file mode 100644 index 0000000..0484b3a --- /dev/null +++ b/0041-conf-cards-add-VC4-HDMI-card.patch @@ -0,0 +1,104 @@ +From 7c2093b1c136e0766116a0b88b565b99176aed19 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 2 Mar 2017 11:49:33 +0100 +Subject: [PATCH 41/43] conf/cards: add VC4-HDMI card + +Add a conf file for the VC4-HDMI sound card. + +Signed-off-by: Boris Brezillon +Tested-by: Eric Anholt +Signed-off-by: Takashi Iwai +--- + src/conf/cards/Makefile.am | 1 + src/conf/cards/aliases.conf | 1 + src/conf/cards/vc4-hdmi.conf | 64 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 66 insertions(+) + create mode 100644 src/conf/cards/vc4-hdmi.conf + +--- a/src/conf/cards/Makefile.am ++++ b/src/conf/cards/Makefile.am +@@ -51,6 +51,7 @@ cfg_files = aliases.conf \ + TRID4DWAVENX.conf \ + USB-Audio.conf \ + YMF744.conf \ ++ vc4-hdmi.conf \ + VIA686A.conf \ + VIA8233.conf \ + VIA8233A.conf \ +--- a/src/conf/cards/aliases.conf ++++ b/src/conf/cards/aliases.conf +@@ -56,6 +56,7 @@ AV200 cards.CMI8788 + CMI8786 cards.CMI8788 + CMI8787 cards.CMI8788 + pistachio cards.pistachio-card ++VC4-HDMI cards.vc4-hdmi + + + +--- /dev/null ++++ b/src/conf/cards/vc4-hdmi.conf +@@ -0,0 +1,64 @@ ++# ++# Configuration for the VC4-HDMI sound card using software IEC958 ++# subframe conversion ++# ++ ++ ++ ++vc4-hdmi.pcm.front.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type hw ++ card $CARD ++} ++ ++# default with dmix ++vc4-hdmi.pcm.default { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type asym ++ playback.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dmix:" $CARD ] ++ } ++ } ++} ++ ++ ++ ++vc4-hdmi.pcm.iec958.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 iec958 ++ slave { ++ format IEC958_SUBFRAME_LE ++ pcm { ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ } ++ } ++ status [ $AES0 $AES1 $AES2 $AES3 ] ++} diff --git a/0042-pcm-plug-save-converter-config.patch b/0042-pcm-plug-save-converter-config.patch new file mode 100644 index 0000000..f31ffc2 --- /dev/null +++ b/0042-pcm-plug-save-converter-config.patch @@ -0,0 +1,63 @@ +From 653faa8991aa3460c42d9688ff83846807f3ad51 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 21 Mar 2017 18:28:18 +0530 +Subject: [PATCH 42/43] pcm:plug: save converter config + +Passed config is freed after call to open, thus it is invalid when +trying to extract the converter name. So config entry is saved +for later usage. + +Signed-off-by: Andreas Pape +Signed-off-by: Mounesh Sutar +Reviewed-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_plug.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/src/pcm/pcm_plug.c ++++ b/src/pcm/pcm_plug.c +@@ -50,7 +50,7 @@ typedef struct { + snd_pcm_format_t sformat; + int schannels; + int srate; +- const snd_config_t *rate_converter; ++ snd_config_t *rate_converter; + enum snd_pcm_plug_route_policy route_policy; + snd_pcm_route_ttable_entry_t *ttable; + int ttable_ok; +@@ -64,6 +64,10 @@ static int snd_pcm_plug_close(snd_pcm_t + snd_pcm_plug_t *plug = pcm->private_data; + int err, result = 0; + free(plug->ttable); ++ if (plug->rate_converter) { ++ snd_config_delete(plug->rate_converter); ++ plug->rate_converter = NULL; ++ } + assert(plug->gen.slave == plug->req_slave); + if (plug->gen.close_slave) { + snd_pcm_unlink_hw_ptr(pcm, plug->req_slave); +@@ -1108,7 +1112,6 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp, + plug->sformat = sformat; + plug->schannels = schannels; + plug->srate = srate; +- plug->rate_converter = rate_converter; + plug->gen.slave = plug->req_slave = slave; + plug->gen.close_slave = close_slave; + plug->route_policy = route_policy; +@@ -1125,6 +1128,15 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp, + pcm->ops = &snd_pcm_plug_ops; + pcm->fast_ops = slave->fast_ops; + pcm->fast_op_arg = slave->fast_op_arg; ++ if (rate_converter) { ++ err = snd_config_copy(&plug->rate_converter, ++ (snd_config_t *)rate_converter); ++ if (err < 0) { ++ snd_pcm_free(pcm); ++ free(plug); ++ return err; ++ } ++ } + pcm->private_data = plug; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; diff --git a/0043-pcm-file-delegate-htimestamping-to-slave-instead-of-.patch b/0043-pcm-file-delegate-htimestamping-to-slave-instead-of-.patch new file mode 100644 index 0000000..275894c --- /dev/null +++ b/0043-pcm-file-delegate-htimestamping-to-slave-instead-of-.patch @@ -0,0 +1,108 @@ +From 01bc7475c3ee4dc0c1c321c781cfb26e6e5fcb34 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Thu, 23 Mar 2017 17:10:45 +0530 +Subject: [PATCH 43/43] pcm:file: delegate htimestamping to slave instead of + always getting real_htimestamp + +purpose of this fix, is to read most accurate timestamps. + + From documentation of /src/pcm/pcm.c, we can see: + """" \par Timestamp mode + + The timestamp mode specifies, if timestamps are activated. Currently, only #SND_PCM_TSTAMP_NONE and #SND_PCM_TSTAMP_MMAP modes are known. + The mmap mode means that timestamp is taken on every period time boundary. Corresponding position in the ring buffer assigned to timestamp can be obtained using #snd_pcm_htimestamp() function. """" + + As snd_pcm_generic_htimestamp() internally calls snd_pcm_htimestamp() to read time, so accurate timestamp can be read from snd_pcm_generic_htimestamp(). + + Also, in case of pcm_file, if the underlying slave is hardware, then we would wish to read elapsed hardware time, as it will be the most accurate, as opposed to the elapsed wall time. + This will provide pcm_file with the most accurate timestamps. + + Following are the timesamps read with timestamp enabled, for with fix and without fix scenarios: + + 1> With fix: +:~#time aplay --enable-tstamp -Dhtstamp_test --period-time=5000 -v -fdat /dev/urandom +Playing raw data '/dev/urandom' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo +File PCM (file=/tmp/swarate_out.wav) +Final file PCM (file=/tmp/swarate_out.wav) +.. + +Slave: Hardware PCM card 0 'imx6q-sabresd-wm8962' device 0 subdevice 0 +Its setup is: + stream : PLAYBACK + access : RW_INTERLEAVED + format : S16_LE + subformat : STD + channels : 2 + rate : 48000 + exact rate : 48000 (48000/1) + msbits : 16 + buffer_size : 24000 + period_size : 240 + period_time : 5000 + tstamp_mode : ENABLE + . + . +Before sleep = 142:409.807623 +After sleep = 142:409.807623 +Before sleep = 142:414.806016 (calling snd_pcm_htimestamp(handle, &avail, &tstamp_before)) +sleep of 2 milisec +After sleep = 142:414.806016 (calling snd_pcm_htimestamp(handle, &avail, &tstamp_after) +From the above timestamps, we can see that slave has returned the same timestamps, as --period-time choosen is 5msec. + +2> Without this fix: +The timestamps are returned with realtime value. + +:~# time aplay --enable-tstamp -Dhtstamp_test --period-time=5000 -v -fdat /dev/urandom +Playing raw data '/dev/urandom' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo +File PCM (file=/tmp/swarate_out.wav) +Final file PCM (file=/tmp/swarate_out.wav) +. +. +Slave: Hardware PCM card 0 'imx6q-sabresd-wm8962' device 0 subdevice 0 +Its setup is: + stream : PLAYBACK + access : RW_INTERLEAVED + format : S16_LE + subformat : STD + channels : 2 + rate : 48000 + exact rate : 48000 (48000/1) + msbits : 16 + buffer_size : 24000 + period_size : 240 + period_time : 5000 + tstamp_mode : ENABLE +. +. +Before sleep = 241:136.875845 (calling snd_pcm_htimestamp(handle, &avail, &tstamp_before)) +sleep of 2 milisec +After sleep = 241:139.076376 (calling snd_pcm_htimestamp(handle, &avail, &tstamp_after) + +We can observe here, the timestamps shows time diff of ~2ms, which is the time gap of sleep duration. +Before sleep = 241:139.617588 +After sleep = 241:141.746845 +Before sleep = 241:142.291618 +After sleep = 241:144.406406 +Before sleep = 241:144.951421 +After sleep = 241:147.066118 +Before sleep = 241:147.623421 +After sleep = 241:149.740573 + +Signed-off-by: Andreas Pape +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -728,7 +728,7 @@ static const snd_pcm_fast_ops_t snd_pcm_ + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +- .htimestamp = snd_pcm_generic_real_htimestamp, ++ .htimestamp = snd_pcm_generic_htimestamp, + }; + + /** diff --git a/alsa.changes b/alsa.changes index 2f6f82b..c366a4b 100644 --- a/alsa.changes +++ b/alsa.changes @@ -1,3 +1,52 @@ +------------------------------------------------------------------- +Wed Mar 29 17:26:08 CEST 2017 - tiwai@suse.de + +- Backport upstream fix patches, including the deadlock fix for + aplay/arecord (boo#1031525): + 0001-ucm-Add-ATTRIBUTE_UNUSED-for-unused-parameters-of-ex.patch + 0002-ucm-parser-needs-limits.h.patch + 0003-pcm-direct-allow-users-to-configure-different-period.patch + 0004-pcm-dshare-enable-silence.patch + 0005-pcm-rate-fix-the-hw_ptr-update-until-the-boundary-av.patch + 0006-plugin-dynamically-update-avail_min-on-slave.patch + 0007-rate-dynamic-update-avail_min-on-slave.patch + 0008-topology-fix-unused-const-variable-warning.patch + 0009-seq-improve-documentation-about-new-get-pid-card-fun.patch + 0010-pcm-direct-returning-semop-error-code-for-semaphore-.patch + 0011-pcm-direct-Fix-for-sync-issue-on-xrun-recover.patch + 0012-pcm-direct-check-state-before-enter-poll-on-timer.patch + 0013-pcm-direct-don-t-return-bogus-buffer-levels-in-xrun-.patch + 0014-conf-ucm-broxton-add-broxton-rt298-conf-files.patch + 0015-pcm-direct-Fix-deadlock-in-poll_descriptors.patch + 0016-ucm-Assure-the-user-input-card-name-not-to-exceed-ma.patch + 0017-ucm-Load-device-specific-configuration-file-based-on.patch + 0018-ucm-Add-command-get-_file-to-get-the-config-file-nam.patch + 0019-topology-Fix-incorrect-license-in-source-comments.patch + 0020-conf-cards-add-support-for-pistachio-card.patch + 0021-pcm-multi-Drop-the-fixed-slave_map-in-snd_pcm_multi_.patch + 0022-conf-Add-card-config-for-Intel-HDMI-DP-LPE-audio.patch + 0023-pcm-Avoid-lock-for-snd_pcm_nonblock.patch + 0024-pcm-Disable-locking-in-async-mode.patch + 0025-pcm-dmix-Allow-disabling-x86-optimizations.patch + 0026-pcm-dmix_rewind-corrupts-application-pointer-fix.patch + 0027-pcm-direct-fix-race-on-clearing-timer-events.patch + 0028-pcm-file-Enable-file-writing-for-capture-path.patch + 0029-pcm-status-dump-fix-timestamp-formatting.patch + 0030-pcm-extplug-refinement-of-masks-in-extplug.patch + 0031-pcm-rate-Add-capability-to-pass-configuration-node-t.patch + 0032-Drop-ppc64-specific-workaround-for-versioned-symbols.patch + 0033-pcm_plugin-unify-the-snd_pcm_mmap_begin-result-value.patch + 0034-always-handle-return-value-from-snd_config_get_id-co.patch + 0035-pcm-file-plugin-handle-snd_pcm_mmap_begin-error-path.patch + 0036-topology-coverity-remove-dead-code.patch + 0037-ucm-parser-fix-possible-string-overflow-in-uc_mgr_im.patch + 0038-dmix-plugin-fix-drain-for-nonblock-mode.patch + 0039-dmix-plugin-drain-quickfix-for-the-previous-patch.patch + 0040-rawmidi-virtual-fix-reading-into-a-small-buffer.patch + 0041-conf-cards-add-VC4-HDMI-card.patch + 0042-pcm-plug-save-converter-config.patch + 0043-pcm-file-delegate-htimestamping-to-slave-instead-of-.patch + ------------------------------------------------------------------- Mon Feb 13 10:28:23 UTC 2017 - tchvatal@suse.com diff --git a/alsa.spec b/alsa.spec index 5e479c4..5c71899 100644 --- a/alsa.spec +++ b/alsa.spec @@ -45,6 +45,49 @@ Source34: alsa-init.sh Source40: 50-alsa.conf Source41: install-snd-module # upstream fixes +Patch1: 0001-ucm-Add-ATTRIBUTE_UNUSED-for-unused-parameters-of-ex.patch +Patch2: 0002-ucm-parser-needs-limits.h.patch +Patch3: 0003-pcm-direct-allow-users-to-configure-different-period.patch +Patch4: 0004-pcm-dshare-enable-silence.patch +Patch5: 0005-pcm-rate-fix-the-hw_ptr-update-until-the-boundary-av.patch +Patch6: 0006-plugin-dynamically-update-avail_min-on-slave.patch +Patch7: 0007-rate-dynamic-update-avail_min-on-slave.patch +Patch8: 0008-topology-fix-unused-const-variable-warning.patch +Patch9: 0009-seq-improve-documentation-about-new-get-pid-card-fun.patch +Patch10: 0010-pcm-direct-returning-semop-error-code-for-semaphore-.patch +Patch11: 0011-pcm-direct-Fix-for-sync-issue-on-xrun-recover.patch +Patch12: 0012-pcm-direct-check-state-before-enter-poll-on-timer.patch +Patch13: 0013-pcm-direct-don-t-return-bogus-buffer-levels-in-xrun-.patch +Patch14: 0014-conf-ucm-broxton-add-broxton-rt298-conf-files.patch +Patch15: 0015-pcm-direct-Fix-deadlock-in-poll_descriptors.patch +Patch16: 0016-ucm-Assure-the-user-input-card-name-not-to-exceed-ma.patch +Patch17: 0017-ucm-Load-device-specific-configuration-file-based-on.patch +Patch18: 0018-ucm-Add-command-get-_file-to-get-the-config-file-nam.patch +Patch19: 0019-topology-Fix-incorrect-license-in-source-comments.patch +Patch20: 0020-conf-cards-add-support-for-pistachio-card.patch +Patch21: 0021-pcm-multi-Drop-the-fixed-slave_map-in-snd_pcm_multi_.patch +Patch22: 0022-conf-Add-card-config-for-Intel-HDMI-DP-LPE-audio.patch +Patch23: 0023-pcm-Avoid-lock-for-snd_pcm_nonblock.patch +Patch24: 0024-pcm-Disable-locking-in-async-mode.patch +Patch25: 0025-pcm-dmix-Allow-disabling-x86-optimizations.patch +Patch26: 0026-pcm-dmix_rewind-corrupts-application-pointer-fix.patch +Patch27: 0027-pcm-direct-fix-race-on-clearing-timer-events.patch +Patch28: 0028-pcm-file-Enable-file-writing-for-capture-path.patch +Patch29: 0029-pcm-status-dump-fix-timestamp-formatting.patch +Patch30: 0030-pcm-extplug-refinement-of-masks-in-extplug.patch +Patch31: 0031-pcm-rate-Add-capability-to-pass-configuration-node-t.patch +Patch32: 0032-Drop-ppc64-specific-workaround-for-versioned-symbols.patch +Patch33: 0033-pcm_plugin-unify-the-snd_pcm_mmap_begin-result-value.patch +Patch34: 0034-always-handle-return-value-from-snd_config_get_id-co.patch +Patch35: 0035-pcm-file-plugin-handle-snd_pcm_mmap_begin-error-path.patch +Patch36: 0036-topology-coverity-remove-dead-code.patch +Patch37: 0037-ucm-parser-fix-possible-string-overflow-in-uc_mgr_im.patch +Patch38: 0038-dmix-plugin-fix-drain-for-nonblock-mode.patch +Patch39: 0039-dmix-plugin-drain-quickfix-for-the-previous-patch.patch +Patch40: 0040-rawmidi-virtual-fix-reading-into-a-small-buffer.patch +Patch41: 0041-conf-cards-add-VC4-HDMI-card.patch +Patch42: 0042-pcm-plug-save-converter-config.patch +Patch43: 0043-pcm-file-delegate-htimestamping-to-slave-instead-of-.patch # rest suse patches BuildRequires: doxygen BuildRequires: libtool @@ -108,6 +151,49 @@ Architecture. %prep %setup -q -n alsa-lib-%{package_version} +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 +%patch43 -p1 %build export AUTOMAKE_JOBS="%{?_smp_mflags}"