Hello community,

here is the log from the commit of package alsa for openSUSE:Factory checked in 
at 2016-06-12 18:51:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/alsa (Old)
 and      /work/SRC/openSUSE:Factory/.alsa.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "alsa"

Changes:
--------
--- /work/SRC/openSUSE:Factory/alsa/alsa.changes        2016-05-19 
12:03:36.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.alsa.new/alsa.changes   2016-06-12 
18:51:38.000000000 +0200
@@ -1,0 +2,15 @@
+Wed Jun  8 10:30:29 CEST 2016 - ti...@suse.de
+
+- Backport upstream fixes: fixing PCM dmix & co suspend/resume,
+  namehint parser fixes, stackable async handler:
+  0007-namehint-Don-t-enumerate-as-duplex-if-only-a-single-.patch
+  0008-pcm-Define-namehint-for-single-directional-PCM-types.patch
+  0009-conf-Add-thread-safe-global-tree-reference.patch
+  0010-pcm-Remove-resume-support-from-dmix-co.patch
+  0011-pcm-Fix-secondary-retry-in-dsnoop-and-dshare.patch
+  0012-pcm-dmix-resume-workaround-for-buggy-driver.patch
+  0013-pcm-dmix-Prepare-slave-when-it-s-in-SETUP-too.patch
+  0014-pcm-dmix-Return-error-when-slave-is-in-OPEN-or-DISCO.patch
+  0015-async-Handle-previously-installed-signal-handler.patch
+
+-------------------------------------------------------------------

New:
----
  0007-namehint-Don-t-enumerate-as-duplex-if-only-a-single-.patch
  0008-pcm-Define-namehint-for-single-directional-PCM-types.patch
  0009-conf-Add-thread-safe-global-tree-reference.patch
  0010-pcm-Remove-resume-support-from-dmix-co.patch
  0011-pcm-Fix-secondary-retry-in-dsnoop-and-dshare.patch
  0012-pcm-dmix-resume-workaround-for-buggy-driver.patch
  0013-pcm-dmix-Prepare-slave-when-it-s-in-SETUP-too.patch
  0014-pcm-dmix-Return-error-when-slave-is-in-OPEN-or-DISCO.patch
  0015-async-Handle-previously-installed-signal-handler.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ alsa.spec ++++++
--- /var/tmp/diff_new_pack.3bnLQM/_old  2016-06-12 18:51:39.000000000 +0200
+++ /var/tmp/diff_new_pack.3bnLQM/_new  2016-06-12 18:51:39.000000000 +0200
@@ -55,6 +55,15 @@
 Patch4:         0004-pcm-softvol-fix-conversion-of-TLVs-min_db-and-max_dB.patch
 Patch5:         0005-pcm-Fix-suspend-resume-regression-with-dmix-co.patch
 Patch6:         0006-pcm-dmix-Fix-doubly-resume-of-slave-PCM.patch
+Patch7:         0007-namehint-Don-t-enumerate-as-duplex-if-only-a-single-.patch
+Patch8:         0008-pcm-Define-namehint-for-single-directional-PCM-types.patch
+Patch9:         0009-conf-Add-thread-safe-global-tree-reference.patch
+Patch10:        0010-pcm-Remove-resume-support-from-dmix-co.patch
+Patch11:        0011-pcm-Fix-secondary-retry-in-dsnoop-and-dshare.patch
+Patch12:        0012-pcm-dmix-resume-workaround-for-buggy-driver.patch
+Patch13:        0013-pcm-dmix-Prepare-slave-when-it-s-in-SETUP-too.patch
+Patch14:        0014-pcm-dmix-Return-error-when-slave-is-in-OPEN-or-DISCO.patch
+Patch15:        0015-async-Handle-previously-installed-signal-handler.patch
 # rest suse patches
 Patch99:        alsa-lib-doxygen-avoid-crash-for-11.3.diff
 # suppress timestamp in documents
@@ -131,6 +140,15 @@
 %patch4 -p1
 %patch5 -p1
 %patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
 %if 0%{?suse_version} == 1130
 %patch99 -p1
 %endif

++++++ 0007-namehint-Don-t-enumerate-as-duplex-if-only-a-single-.patch ++++++
>From 8cdbdae73109c901aec4984f6ba65e5b25722f13 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Thu, 12 May 2016 16:30:44 +0200
Subject: [PATCH 07/15] namehint: Don't enumerate as duplex if only a single
 direction is defined

When a hint description has only either device_input or device_output,
we shouldn't handle it as a full duplex but rather a single
direction.  In that way, we can avoid to list up a playback stream
like dmix or surround51 as a capture stream in the namehint.

Reported-by: Trent Reed <treed0...@gmail.com>
Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/control/namehint.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/control/namehint.c b/src/control/namehint.c
index 856957c76d74..ad8dda37a637 100644
--- a/src/control/namehint.c
+++ b/src/control/namehint.c
@@ -28,6 +28,7 @@
 #include "local.h"
 
 #ifndef DOC_HIDDEN
+#define DEV_SKIP       9999 /* some non-existing device number */
 struct hint_list {
        char **list;
        unsigned int count;
@@ -90,7 +91,7 @@ static int get_dev_name1(struct hint_list *list, char **res, 
int device,
                         int stream)
 {
        *res = NULL;
-       if (device < 0)
+       if (device < 0 || device == DEV_SKIP)
                return 0;
        switch (list->iface) {
 #ifdef BUILD_HWDEP
@@ -317,7 +318,9 @@ static int try_config(snd_config_t *config,
                                err = -EINVAL;
                                goto __cleanup;
                        }
-                       list->device_output = -1;
+                       /* skip the counterpart if only a single direction is 
defined */
+                       if (list->device_output < 0)
+                               list->device_output = DEV_SKIP;
                }
                if (snd_config_search(cfg, "device_output", &n) >= 0) {
                        if (snd_config_get_integer(n, &list->device_output) < 
0) {
@@ -325,6 +328,9 @@ static int try_config(snd_config_t *config,
                                err = -EINVAL;
                                goto __cleanup;
                        }
+                       /* skip the counterpart if only a single direction is 
defined */
+                       if (list->device_input < 0)
+                               list->device_input = DEV_SKIP;
                }
        } else if (level == 1 && !list->show_all)
                goto __skip_add;
-- 
2.8.3

++++++ 0008-pcm-Define-namehint-for-single-directional-PCM-types.patch ++++++
>From 5fb3fe17249c3fffb8b8e15108ff72f27ba5e81c Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Thu, 12 May 2016 16:33:19 +0200
Subject: [PATCH 08/15] pcm: Define namehint for single directional PCM types

The PCM namehint for some PCM types like dmix, dsnoop and surround51
should be defined as single directional.

Reported-by: Trent Reed <treed0...@gmail.com>
Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/conf/pcm/dmix.conf       | 2 +-
 src/conf/pcm/dsnoop.conf     | 2 +-
 src/conf/pcm/surround21.conf | 2 +-
 src/conf/pcm/surround40.conf | 2 +-
 src/conf/pcm/surround41.conf | 2 +-
 src/conf/pcm/surround50.conf | 2 +-
 src/conf/pcm/surround51.conf | 2 +-
 src/conf/pcm/surround71.conf | 2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf
index e62cb295278c..7d0aa0158c42 100644
--- a/src/conf/pcm/dmix.conf
+++ b/src/conf/pcm/dmix.conf
@@ -110,6 +110,6 @@ pcm.!dmix {
                        name defaults.namehint.extended
                }
                description "Direct sample mixing device"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/dsnoop.conf b/src/conf/pcm/dsnoop.conf
index 49cfca98c262..abbd44f7fd79 100644
--- a/src/conf/pcm/dsnoop.conf
+++ b/src/conf/pcm/dsnoop.conf
@@ -110,6 +110,6 @@ pcm.!dsnoop {
                        name defaults.namehint.extended
                }
                description "Direct sample snooping device"
-               device $DEV
+               device_input $DEV
        }
 }
diff --git a/src/conf/pcm/surround21.conf b/src/conf/pcm/surround21.conf
index 7f4676b3f714..1cf1b7af8dc6 100644
--- a/src/conf/pcm/surround21.conf
+++ b/src/conf/pcm/surround21.conf
@@ -56,6 +56,6 @@ pcm.!surround21 {
        ttable.2.LFE 1
        hint {
                description "2.1 Surround output to Front and Subwoofer 
speakers"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/surround40.conf b/src/conf/pcm/surround40.conf
index 361ccaa1e329..9788ad4884fd 100644
--- a/src/conf/pcm/surround40.conf
+++ b/src/conf/pcm/surround40.conf
@@ -54,6 +54,6 @@ pcm.!surround40 {
        }
        hint {
                description "4.0 Surround output to Front and Rear speakers"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf
index 2f823815821a..7b4ef3beb43a 100644
--- a/src/conf/pcm/surround41.conf
+++ b/src/conf/pcm/surround41.conf
@@ -60,6 +60,6 @@ pcm.!surround41 {
        ttable.4.LFE 1
        hint {
                description "4.1 Surround output to Front, Rear and Subwoofer 
speakers"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf
index dc95c179da68..7d9a9e798fd8 100644
--- a/src/conf/pcm/surround50.conf
+++ b/src/conf/pcm/surround50.conf
@@ -60,6 +60,6 @@ pcm.!surround50 {
        ttable.4.FC 1
        hint {
                description "5.0 Surround output to Front, Center and Rear 
speakers"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/surround51.conf b/src/conf/pcm/surround51.conf
index 3a7543f9fb8a..e67f007ef305 100644
--- a/src/conf/pcm/surround51.conf
+++ b/src/conf/pcm/surround51.conf
@@ -56,6 +56,6 @@ pcm.!surround51 {
        }
        hint {
                description "5.1 Surround output to Front, Center, Rear and 
Subwoofer speakers"
-               device $DEV
+               device_output $DEV
        }
 }
diff --git a/src/conf/pcm/surround71.conf b/src/conf/pcm/surround71.conf
index 076a97d73716..a26c3f36c437 100644
--- a/src/conf/pcm/surround71.conf
+++ b/src/conf/pcm/surround71.conf
@@ -58,6 +58,6 @@ pcm.!surround71 {
        }
        hint {
                description "7.1 Surround output to Front, Center, Side, Rear 
and Woofer speakers"
-               device $DEV
+               device_output $DEV
        }
 }
-- 
2.8.3

++++++ 0009-conf-Add-thread-safe-global-tree-reference.patch ++++++
>From c9a0d7d601e8ab069f8745968c03c8470b24d20d Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Tue, 17 May 2016 15:39:07 +0200
Subject: [PATCH 09/15] conf: Add thread-safe global tree reference

Most of open functions in alsa-lib have the call pattern:
  snd_config_update();
  return snd_xxx_open(x, snd_config, ...);

This means that the toplevel config gets updated, and passed to a
local open function.  Although snd_config_update() itself has a
pthread mutex to be thread safe, the whole procedure above isn't
thread safe.  Namely, the global snd_config tree may be deleted and
recreated at any time while the open function is being processed.
This may lead to a data corruption and crash of the program.

For avoiding the corruption, this patch introduces a refcount to
config tree object.  A few new helper functions are introduced as
well:
- snd_config_update_ref() does update and take the refcount of the
  toplevel tree.   The obtained config tree has to be freed via
  snd_config_unref() below.
- snd_config_ref() and snd_config_unref() manage the refcount of the
  config object.  The latter eventually deletes the object when all
  references are gone.

Along with these additions, the caller of snd_config_update() and
snd_config global tree in alsa-lib are replaced with the new helpers.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 include/conf.h          |  4 +++
 src/conf.c              | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/control/control.c   |  8 +++--
 src/hwdep/hwdep.c       |  8 +++--
 src/pcm/pcm.c           |  8 +++--
 src/rawmidi/rawmidi.c   |  8 +++--
 src/seq/seq.c           |  8 +++--
 src/timer/timer.c       |  8 +++--
 src/timer/timer_query.c |  8 +++--
 9 files changed, 125 insertions(+), 14 deletions(-)

diff --git a/include/conf.h b/include/conf.h
index 087c05dc6bcf..5d293d583fbb 100644
--- a/include/conf.h
+++ b/include/conf.h
@@ -94,6 +94,10 @@ int snd_config_update_r(snd_config_t **top, 
snd_config_update_t **update, const
 int snd_config_update_free(snd_config_update_t *update);
 int snd_config_update_free_global(void);
 
+int snd_config_update_ref(snd_config_t **top);
+void snd_config_ref(snd_config_t *top);
+void snd_config_unref(snd_config_t *top);
+
 int snd_config_search(snd_config_t *config, const char *key,
                      snd_config_t **result);
 int snd_config_searchv(snd_config_t *config, 
diff --git a/src/conf.c b/src/conf.c
index f8b7a6686529..a516611427ac 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -434,6 +434,7 @@ static pthread_once_t snd_config_update_mutex_once = 
PTHREAD_ONCE_INIT;
 struct _snd_config {
        char *id;
        snd_config_type_t type;
+       int refcount; /* default = 0 */
        union {
                long integer;
                long long integer64;
@@ -1825,6 +1826,10 @@ int snd_config_remove(snd_config_t *config)
  * If the node is a compound node, its descendants (the whole subtree)
  * are deleted recursively.
  *
+ * The function is supposed to be called only for locally copied config
+ * trees.  For the global tree, take the reference via #snd_config_update_ref
+ * and free it via #snd_config_unref.
+ *
  * \par Conforming to:
  * LSB 3.2
  *
@@ -1833,6 +1838,10 @@ int snd_config_remove(snd_config_t *config)
 int snd_config_delete(snd_config_t *config)
 {
        assert(config);
+       if (config->refcount > 0) {
+               config->refcount--;
+               return 0;
+       }
        switch (config->type) {
        case SND_CONFIG_TYPE_COMPOUND:
        {
@@ -3833,6 +3842,8 @@ int snd_config_update_r(snd_config_t **_top, 
snd_config_update_t **_update, cons
  * \warning Whenever #snd_config is updated, all string pointers and
  * configuration node handles previously obtained from it may become
  * invalid.
+ * For safer operations, use #snd_config_update_ref and release the config
+ * via #snd_config_unref.
  *
  * \par Errors:
  * Any errors encountered when parsing the input or returned by hooks or
@@ -3851,6 +3862,74 @@ int snd_config_update(void)
        return err;
 }
 
+/**
+ * \brief Updates #snd_config and takes its reference.
+ * \return 0 if #snd_config was up to date, 1 if #snd_config was
+ *         updated, otherwise a negative error code.
+ *
+ * Unlike #snd_config_update, this function increases a reference counter
+ * so that the obtained tree won't be deleted until unreferenced by
+ * #snd_config_unref.
+ *
+ * This function is supposed to be thread-safe.
+ */
+int snd_config_update_ref(snd_config_t **top)
+{
+       int err;
+
+       if (top)
+               *top = NULL;
+       snd_config_lock();
+       err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
+       if (err >= 0) {
+               if (snd_config) {
+                       if (top) {
+                               snd_config->refcount++;
+                               *top = snd_config;
+                       }
+               } else {
+                       err = -ENODEV;
+               }
+       }
+       snd_config_unlock();
+       return err;
+}
+
+/**
+ * \brief Take the reference of the config tree.
+ *
+ * Increases a reference counter of the given config tree.
+ *
+ * This function is supposed to be thread-safe.
+ */
+void snd_config_ref(snd_config_t *cfg)
+{
+       snd_config_lock();
+       if (cfg)
+               cfg->refcount++;
+       snd_config_unlock();
+}
+
+/**
+ * \brief Unreference the config tree.
+ *
+ * Decreases a reference counter of the given config tree, and eventually
+ * deletes the tree if all references are gone.  This is the counterpart of
+ * #snd_config_unref.
+ *
+ * Also, the config taken via #snd_config_update_ref must be unreferenced
+ * by this function, too.
+ *
+ * This function is supposed to be thread-safe.
+ */
+void snd_config_unref(snd_config_t *cfg)
+{
+       snd_config_lock();
+       if (cfg)
+               snd_config_delete(cfg);
+       snd_config_unlock();
+}
+
 /** 
  * \brief Frees a private update structure.
  * \param[in] update The private update structure to free.
diff --git a/src/control/control.c b/src/control/control.c
index 8a5d530f2674..ae7884313c63 100644
--- a/src/control/control.c
+++ b/src/control/control.c
@@ -968,12 +968,16 @@ static int snd_ctl_open_noupdate(snd_ctl_t **ctlp, 
snd_config_t *root, const cha
  */
 int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(ctlp && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_ctl_open_noupdate(ctlp, snd_config, name, mode);
+       err = snd_ctl_open_noupdate(ctlp, top, name, mode);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c
index 5dc791c99189..bac634bae14a 100644
--- a/src/hwdep/hwdep.c
+++ b/src/hwdep/hwdep.c
@@ -168,12 +168,16 @@ static int snd_hwdep_open_noupdate(snd_hwdep_t **hwdep, 
snd_config_t *root, cons
  */
 int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(hwdep && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_hwdep_open_noupdate(hwdep, snd_config, name, mode);
+       err = snd_hwdep_open_noupdate(hwdep, top, name, mode);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 203e7a52491b..0d0d093deb49 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -2288,12 +2288,16 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, 
snd_config_t *root,
 int snd_pcm_open(snd_pcm_t **pcmp, const char *name, 
                 snd_pcm_stream_t stream, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(pcmp && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
+       err = snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index 0c89b8b984b9..4701b4375359 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -305,12 +305,16 @@ static int snd_rawmidi_open_noupdate(snd_rawmidi_t 
**inputp, snd_rawmidi_t **out
 int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
                     const char *name, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert((inputp || outputp) && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_rawmidi_open_noupdate(inputp, outputp, snd_config, name, 
mode);
+       err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/seq/seq.c b/src/seq/seq.c
index 4405e68a7fe9..92798308a3b0 100644
--- a/src/seq/seq.c
+++ b/src/seq/seq.c
@@ -974,12 +974,16 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, 
snd_config_t *root,
 int snd_seq_open(snd_seq_t **seqp, const char *name, 
                 int streams, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(seqp && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0);
+       err = snd_seq_open_noupdate(seqp, top, name, streams, mode, 0);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/timer/timer.c b/src/timer/timer.c
index a25e4f797ce4..b25347117cba 100644
--- a/src/timer/timer.c
+++ b/src/timer/timer.c
@@ -201,12 +201,16 @@ static int snd_timer_open_noupdate(snd_timer_t **timer, 
snd_config_t *root, cons
  */
 int snd_timer_open(snd_timer_t **timer, const char *name, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(timer && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_timer_open_noupdate(timer, snd_config, name, mode);
+       err = snd_timer_open_noupdate(timer, top, name, mode);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
diff --git a/src/timer/timer_query.c b/src/timer/timer_query.c
index 93d2455d07fc..2072ceaea349 100644
--- a/src/timer/timer_query.c
+++ b/src/timer/timer_query.c
@@ -159,12 +159,16 @@ static int 
snd_timer_query_open_noupdate(snd_timer_query_t **timer, snd_config_t
  */
 int snd_timer_query_open(snd_timer_query_t **timer, const char *name, int mode)
 {
+       snd_config_t *top;
        int err;
+
        assert(timer && name);
-       err = snd_config_update();
+       err = snd_config_update_ref(&top);
        if (err < 0)
                return err;
-       return snd_timer_query_open_noupdate(timer, snd_config, name, mode);
+       err = snd_timer_query_open_noupdate(timer, top, name, mode);
+       snd_config_unref(top);
+       return err;
 }
 
 /**
-- 
2.8.3

++++++ 0010-pcm-Remove-resume-support-from-dmix-co.patch ++++++
>From d942498bfbd315c4c4559ccd573685e09aa03383 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Wed, 18 May 2016 10:38:27 +0200
Subject: [PATCH 10/15] pcm: Remove resume support from dmix & co

PCM dmix and other plugins inherit the resume behavior from the slave
PCM.  However, the resume on dmix can't work reliably even if the
slave PCM may do resume.  The running state of each dmix stream is
individual and may be PREPARED or RUN_PENDING while the slave PCM is
already in RUNNING.  And, when the slave PCM is resumed, the whole
samples that have been already mapped are also played back, even if
the corresponding dmix stream is still in SUSPENDED.  Such
inconsistencies can't be avoided as long as we manage each stream
individually.

That said, dmix & co can't provide the proper resume support "by
design".  For aligning with it, we should drop the whole resume code
and clear the PCM SND_PCM_INFO_RESUME flag.

Reported-by: Shengjiu Wang <shengjiu.w...@nxp.com>
Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/pcm/pcm_direct.c | 24 ++----------------------
 1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index ac082f1a73b2..53c49929cb1f 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -837,27 +837,7 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
 
 int snd_pcm_direct_resume(snd_pcm_t *pcm)
 {
-       snd_pcm_direct_t *dmix = pcm->private_data;
-       int err;
-       
-       snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
-       /* resume only when the slave PCM is still in suspended state */
-       if (snd_pcm_state(dmix->spcm) != SND_PCM_STATE_SUSPENDED) {
-               err = 0;
-               goto out;
-       }
-
-       err = snd_pcm_resume(dmix->spcm);
-       if (err == -ENOSYS) {
-               /* FIXME: error handling? */
-               snd_pcm_prepare(dmix->spcm);
-               snd_pcm_start(dmix->spcm);
-               err = 0;
-       }
- out:
-       dmix->state = snd_pcm_state(dmix->spcm);
-       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
-       return err;
+       return -ENOSYS;
 }
 
 #define COPY_SLAVE(field) (dmix->shmptr->s.field = spcm->field)
@@ -865,7 +845,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 /* copy the slave setting */
 static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 {
-       spcm->info &= ~SND_PCM_INFO_PAUSE;
+       spcm->info &= ~(SND_PCM_INFO_PAUSE | SND_PCM_INFO_RESUME);
 
        COPY_SLAVE(access);
        COPY_SLAVE(format);
-- 
2.8.3

++++++ 0011-pcm-Fix-secondary-retry-in-dsnoop-and-dshare.patch ++++++
>From 2fa36eb03c000560128f7abce701536546b4a618 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Sat, 28 May 2016 10:37:26 +0200
Subject: [PATCH 11/15] pcm: Fix secondary retry in dsnoop and dshare

The commit [fdba9e1bad8f: pcm: Fallback open as the first instance for
dmix & co] introduced a mechanism to retry the open of slave PCM for
the secondary streams, but this also introduced a regression in dsnoop
and dshare plugins: since the retry goto-tag was placed at a wrong
position, it retries to re-fetch the shm unnecessarily and eventually
leads to the fatal error.

The bug can be easily reproduced by starting arecord and killing it
via SIGKILL, then starting arecord again.  The second arecord fails.

The fix is obviously to move the wrong retry goto-tags to the right
positions.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/pcm/pcm_dshare.c | 2 +-
 src/pcm/pcm_dsnoop.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index adb3587a2869..05854dedf259 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -690,7 +690,6 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
                break;
        }
 
- retry:
        first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare);
        if (ret < 0) {
                SNDERR("unable to create IPC shm instance");
@@ -705,6 +704,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
        dshare->max_periods = opts->max_periods;
        dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
 
+ retry:
        if (first_instance) {
                /* recursion is already checked in
                   snd_pcm_direct_get_slave_ipc_offset() */
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index 8ff0ba57cb14..2d45171dda01 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -583,7 +583,6 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
                break;
        }
                
- retry:
        first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
        if (ret < 0) {
                SNDERR("unable to create IPC shm instance");
@@ -598,6 +597,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
        dsnoop->max_periods = opts->max_periods;
        dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
 
+ retry:
        if (first_instance) {
                /* recursion is already checked in
                   snd_pcm_direct_get_slave_ipc_offset() */
-- 
2.8.3

++++++ 0012-pcm-dmix-resume-workaround-for-buggy-driver.patch ++++++
>From 6d1d620eadf32c6d963468ce56ff52cc3a2f32e2 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Wed, 25 May 2016 15:03:51 +0200
Subject: [PATCH 12/15] pcm: dmix: resume workaround for buggy driver

The previous commit removed the whole handling of resume in dmix, but
this seems causing another regression; some buggy drivers assume that
the device-resume needs to be triggered before transitioning to
PREPARED state.  As an ugly workaround, in this patch, when the slave
PCM supports resume, snd_pcm_direct_resume() does resume of the slave
PCM but immediately drop the stream after that.  In that way, the
device is brought to the sane active state, then the apps can prepare
and restart the stream properly.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/pcm/pcm_direct.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 53c49929cb1f..343fd3c6da3c 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -837,6 +837,27 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
 
 int snd_pcm_direct_resume(snd_pcm_t *pcm)
 {
+       snd_pcm_direct_t *dmix = pcm->private_data;
+       snd_pcm_t *spcm = dmix->spcm;
+
+       snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+       /* some buggy drivers require the device resumed before prepared;
+        * when a device has RESUME flag and is in SUSPENDED state, resume
+        * here but immediately drop to bring it to a sane active state.
+        */
+       if ((spcm->info & SND_PCM_INFO_RESUME) &&
+           snd_pcm_state(spcm) == SND_PCM_STATE_SUSPENDED) {
+               snd_pcm_resume(spcm);
+               snd_pcm_drop(spcm);
+               snd_pcm_direct_timer_stop(dmix);
+               snd_pcm_direct_clear_timer_queue(dmix);
+               snd_pcm_areas_silence(snd_pcm_mmap_areas(spcm), 0,
+                                     spcm->channels, spcm->buffer_size,
+                                     spcm->format);
+               snd_pcm_prepare(spcm);
+               snd_pcm_start(spcm);
+       }
+       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
        return -ENOSYS;
 }
 
@@ -845,7 +866,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 /* copy the slave setting */
 static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 {
-       spcm->info &= ~(SND_PCM_INFO_PAUSE | SND_PCM_INFO_RESUME);
+       spcm->info &= ~SND_PCM_INFO_PAUSE;
 
        COPY_SLAVE(access);
        COPY_SLAVE(format);
@@ -874,6 +895,8 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, 
snd_pcm_t *spcm)
        COPY_SLAVE(buffer_time);
        COPY_SLAVE(sample_bits);
        COPY_SLAVE(frame_bits);
+
+       dmix->shmptr->s.info &= ~SND_PCM_INFO_RESUME;
 }
 
 #undef COPY_SLAVE
-- 
2.8.3

++++++ 0013-pcm-dmix-Prepare-slave-when-it-s-in-SETUP-too.patch ++++++
>From 8feb96ed9b457c2aa62ddea2c48651475b7c3411 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Tue, 31 May 2016 12:46:03 +0200
Subject: [PATCH 13/15] pcm: dmix: Prepare slave when it's in SETUP, too

SETUP is an unusual state, but it's still possible.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/pcm/pcm_direct.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 343fd3c6da3c..fbf9a592a4bc 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -819,6 +819,7 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
        int err;
 
        switch (snd_pcm_state(dmix->spcm)) {
+       case SND_PCM_STATE_SETUP:
        case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
        case SND_PCM_STATE_DISCONNECTED:
-- 
2.8.3

++++++ 0014-pcm-dmix-Return-error-when-slave-is-in-OPEN-or-DISCO.patch ++++++
>From 614ce73d3d6eba13946f863bec24981d355902e1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <ti...@suse.de>
Date: Tue, 31 May 2016 12:48:40 +0200
Subject: [PATCH 14/15] pcm: dmix: Return error when slave is in OPEN or
 DISCONNECTED

A slave PCM in OPEN or DISCONNECTED state can't be used properly at
all, so the best option is to return -EBADFD error.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/pcm/pcm_direct.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index fbf9a592a4bc..21f98e7a1779 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -822,12 +822,14 @@ int snd_pcm_direct_prepare(snd_pcm_t *pcm)
        case SND_PCM_STATE_SETUP:
        case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
-       case SND_PCM_STATE_DISCONNECTED:
                err = snd_pcm_prepare(dmix->spcm);
                if (err < 0)
                        return err;
                snd_pcm_start(dmix->spcm);
                break;
+       case SND_PCM_STATE_OPEN:
+       case SND_PCM_STATE_DISCONNECTED:
+               return -EBADFD;
        }
        snd_pcm_direct_check_interleave(dmix, pcm);
        dmix->state = SND_PCM_STATE_PREPARED;
-- 
2.8.3

++++++ 0015-async-Handle-previously-installed-signal-handler.patch ++++++
>From d39e1879b9c72d51fe1ca4aeb5ba742e97b2175a Mon Sep 17 00:00:00 2001
From: Eliot Miranda <eliot.mira...@gmail.com>
Date: Wed, 1 Jun 2016 08:16:31 +0200
Subject: [PATCH 15/15] async: Handle previously installed signal handler

The issue is with the signal handler installed and deinstalled in
alsa-lib async handler.  This code makes no attempt to remember any
previously installed signal handlers for SIGIO, if SIGIO is used.
Consequently it does not call any previous handlers from its own
handler once installed, and does not reinstall any previous handler
when deinstalling its handler.  Consequently, use of also-lib within
applications that depend on SIGIO will break those applications,
rendering them inoperative once alsa-lib is running because their
signal handlers are no longer called.

This patch does remember and restore any previous handler, and chains
calls to the handler if it exists.

Signed-off-by: Takashi Iwai <ti...@suse.de>
---
 src/async.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/src/async.c b/src/async.c
index 98aec78e00a8..0e133c3a34cd 100644
--- a/src/async.c
+++ b/src/async.c
@@ -28,6 +28,9 @@
 #include "control/control_local.h"
 #include <signal.h>
 
+static struct sigaction previous_action;
+#define MAX_SIG_FUNCTION_CODE 10 /* i.e. SIG_DFL SIG_IGN SIG_HOLD et al */
+
 #ifdef SND_ASYNC_RT_SIGNAL
 /** async signal number */
 static int snd_async_signo;
@@ -54,6 +57,9 @@ static void snd_async_handler(int signo ATTRIBUTE_UNUSED, 
siginfo_t *siginfo, vo
        int fd;
        struct list_head *i;
        //assert(siginfo->si_code == SI_SIGIO);
+       if (signo == SIGIO
+        && (unsigned long)(previous_action.sa_sigaction) > 
MAX_SIG_FUNCTION_CODE)
+               previous_action.sa_sigaction(signo, siginfo, context);
        fd = siginfo->si_fd;
        list_for_each(i, &snd_async_handlers) {
                snd_async_handler_t *h = list_entry(i, snd_async_handler_t, 
glist);
@@ -114,7 +120,8 @@ int snd_async_add_handler(snd_async_handler_t **handler, 
int fd,
                act.sa_flags = SA_RESTART | SA_SIGINFO;
                act.sa_sigaction = snd_async_handler;
                sigemptyset(&act.sa_mask);
-               err = sigaction(snd_async_signo, &act, NULL);
+               assert(!previous_action.sa_sigaction);
+               err = sigaction(snd_async_signo, &act, &previous_action);
                if (err < 0) {
                        SYSERR("sigaction");
                        return -errno;
@@ -131,18 +138,17 @@ int snd_async_add_handler(snd_async_handler_t **handler, 
int fd,
 int snd_async_del_handler(snd_async_handler_t *handler)
 {
        int err = 0;
+       int was_empty = list_empty(&snd_async_handlers);
        assert(handler);
        list_del(&handler->glist);
-       if (list_empty(&snd_async_handlers)) {
-               struct sigaction act;
-               memset(&act, 0, sizeof(act));
-               act.sa_flags = 0;
-               act.sa_handler = SIG_DFL;
-               err = sigaction(snd_async_signo, &act, NULL);
+       if (!was_empty
+        && list_empty(&snd_async_handlers)) {
+               err = sigaction(snd_async_signo, &previous_action, NULL);
                if (err < 0) {
                        SYSERR("sigaction");
                        return -errno;
                }
+               memset(&previous_action, 0, sizeof(previous_action));
        }
        if (handler->type == SND_ASYNC_HANDLER_GENERIC)
                goto _end;
-- 
2.8.3





Reply via email to