Hello community,

here is the log from the commit of package alsa for openSUSE:Factory checked in 
at 2015-08-21 07:37:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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        2015-07-05 
18:00:30.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.alsa.new/alsa.changes   2015-08-21 
07:37:19.000000000 +0200
@@ -1,0 +2,43 @@
+Tue Aug  4 17:41:39 CEST 2015 - [email protected]
+
+- Backport upstream fixes: surround41/50 chmap fix, UCM documents,
+  config string fix, PCM timestamp query API, replacement of list.h
+  with LGPL:
+  0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
+  0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
+  0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
+  0026-docs-Add-UCM-link-to-main-doxygen-page.patch
+  0027-Replace-unsafe-characters-with-_-in-card-name.patch
+  0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
+  0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
+  0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
+  0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
+  0032-test-audio_time-show-report-validity-and-accuracy.patch
+  0033-pcm-restore-hw-params-on-set-latency-failed.patch
+  0034-Replace-list.h-with-its-own-version.patch
+- Backport topology API addition patches:
+  0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
+  0036-topology-Add-topology-core-parser.patch
+  0037-topology-Add-text-section-parser.patch
+  0038-topology-Add-PCM-parser.patch
+  0039-topology-Add-operations-parser.patch
+  0040-topology-Add-private-data-parser.patch
+  0041-topology-Add-DAPM-object-parser.patch
+  0042-topology-Add-CTL-parser.patch
+  0043-topology-Add-Channel-map-parser.patch
+  0044-topology-Add-binary-file-builder.patch
+  0045-topology-autotools-Add-build-support-for-topology-co.patch
+  0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
+  0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
+  0048-topology-Fix-missing-inclusion-of-ctype.h.patch
+  0049-topology-Fix-typos.patch
+- Enable autoreconf call to regenerate after patching
+
+-------------------------------------------------------------------
+Fri Jul 31 07:35:12 UTC 2015 - [email protected]
+
+- Change libudev-devel BuildRequires to pkgconfig(udev): makes us
+  less prone to packaging changes, and in the end udev.pc is
+  exactly what we need to define _udevdir.
+
+-------------------------------------------------------------------

New:
----
  0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
  0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
  0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
  0026-docs-Add-UCM-link-to-main-doxygen-page.patch
  0027-Replace-unsafe-characters-with-_-in-card-name.patch
  0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
  0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
  0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
  0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
  0032-test-audio_time-show-report-validity-and-accuracy.patch
  0033-pcm-restore-hw-params-on-set-latency-failed.patch
  0034-Replace-list.h-with-its-own-version.patch
  0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
  0036-topology-Add-topology-core-parser.patch
  0037-topology-Add-text-section-parser.patch
  0038-topology-Add-PCM-parser.patch
  0039-topology-Add-operations-parser.patch
  0040-topology-Add-private-data-parser.patch
  0041-topology-Add-DAPM-object-parser.patch
  0042-topology-Add-CTL-parser.patch
  0043-topology-Add-Channel-map-parser.patch
  0044-topology-Add-binary-file-builder.patch
  0045-topology-autotools-Add-build-support-for-topology-co.patch
  0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
  0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
  0048-topology-Fix-missing-inclusion-of-ctype.h.patch
  0049-topology-Fix-typos.patch

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

Other differences:
------------------
++++++ alsa.spec ++++++
--- /var/tmp/diff_new_pack.WnaeCZ/_old  2015-08-21 07:37:21.000000000 +0200
+++ /var/tmp/diff_new_pack.WnaeCZ/_new  2015-08-21 07:37:21.000000000 +0200
@@ -71,6 +71,33 @@
 Patch20:        0020-pcm-Fix-snd_pcm_status-for-dmix-co.patch
 Patch21:        0021-control-Allow-cset-ing-specific-values-in-the-multi-.patch
 Patch22:        0022-PCM-snd_pcm_xxxx_drain-maybe-blocked-after-suspend-a.patch
+Patch23:        0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch
+Patch24:        0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch
+Patch25:        0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch
+Patch26:        0026-docs-Add-UCM-link-to-main-doxygen-page.patch
+Patch27:        0027-Replace-unsafe-characters-with-_-in-card-name.patch
+Patch28:        0028-pcm-add-helper-functions-to-query-timestamping-capab.patch
+Patch29:        0029-pcm-add-support-for-get-set_audio_htstamp_config.patch
+Patch30:        0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch
+Patch31:        0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch
+Patch32:        0032-test-audio_time-show-report-validity-and-accuracy.patch
+Patch33:        0033-pcm-restore-hw-params-on-set-latency-failed.patch
+Patch34:        0034-Replace-list.h-with-its-own-version.patch
+Patch35:        0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch
+Patch36:        0036-topology-Add-topology-core-parser.patch
+Patch37:        0037-topology-Add-text-section-parser.patch
+Patch38:        0038-topology-Add-PCM-parser.patch
+Patch39:        0039-topology-Add-operations-parser.patch
+Patch40:        0040-topology-Add-private-data-parser.patch
+Patch41:        0041-topology-Add-DAPM-object-parser.patch
+Patch42:        0042-topology-Add-CTL-parser.patch
+Patch43:        0043-topology-Add-Channel-map-parser.patch
+Patch44:        0044-topology-Add-binary-file-builder.patch
+Patch45:        0045-topology-autotools-Add-build-support-for-topology-co.patch
+Patch46:        0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch
+Patch47:        0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch
+Patch48:        0048-topology-Fix-missing-inclusion-of-ctype.h.patch
+Patch49:        0049-topology-Fix-typos.patch
 # rest suse patches
 Patch99:        alsa-lib-doxygen-avoid-crash-for-11.3.diff
 # suppress timestamp in documents
@@ -86,7 +113,7 @@
 Recommends:     alsa-plugins
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 %if 0%{?suse_version} > 1200
-BuildRequires:  libudev-devel
+BuildRequires:  pkgconfig(udev)
 %else
 BuildRequires:  udev
 %endif
@@ -163,6 +190,33 @@
 %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
+%patch44 -p1
+%patch45 -p1
+%patch46 -p1
+%patch47 -p1
+%patch48 -p1
+%patch49 -p1
 %if 0%{?suse_version} == 1130
 %patch99 -p1
 %endif
@@ -178,7 +232,7 @@
 %build
 export AUTOMAKE_JOBS="%{?_smp_mflags}"
 # build alsa-lib
-# autoreconf -fi
+autoreconf -fi
 %configure \
   --disable-static \
   --enable-symbolic-functions \

++++++ 0023-surround41-50.conf-Use-chmap-syntax-for-better-flexi.patch ++++++
>From bbe9248e6788e7a852af15f2110dbaeace4d1907 Mon Sep 17 00:00:00 2001
From: David Henningsson <[email protected]>
Date: Thu, 18 Jun 2015 10:47:59 +0200
Subject: [PATCH] surround41/50.conf: Use chmap syntax for better flexibility

In case the hardware only supports a specific channel map,
this change would allow surround41/50 to select the correct
channel map and channel count in this situation.

Signed-off-by: David Henningsson <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/conf/pcm/surround41.conf | 11 +++++------
 src/conf/pcm/surround50.conf | 11 +++++------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf
index 10e486e21528..2f823815821a 100644
--- a/src/conf/pcm/surround41.conf
+++ b/src/conf/pcm/surround41.conf
@@ -53,12 +53,11 @@ pcm.!surround41 {
                        ]
                }
        }
-       slave.channels 6
-       ttable.0.0 1
-       ttable.1.1 1
-       ttable.2.2 1
-       ttable.3.3 1
-       ttable.4.5 1
+       ttable.0.FL 1
+       ttable.1.FR 1
+       ttable.2.RL 1
+       ttable.3.RR 1
+       ttable.4.LFE 1
        hint {
                description "4.1 Surround output to Front, Rear and Subwoofer 
speakers"
                device $DEV
diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf
index 7b7b17e10246..dc95c179da68 100644
--- a/src/conf/pcm/surround50.conf
+++ b/src/conf/pcm/surround50.conf
@@ -53,12 +53,11 @@ pcm.!surround50 {
                        ]
                }
        }
-       slave.channels 6
-       ttable.0.0 1
-       ttable.1.1 1
-       ttable.2.2 1
-       ttable.3.3 1
-       ttable.4.4 1
+       ttable.0.FL 1
+       ttable.1.FR 1
+       ttable.2.RL 1
+       ttable.3.RR 1
+       ttable.4.FC 1
        hint {
                description "5.0 Surround output to Front, Center and Rear 
speakers"
                device $DEV
-- 
2.5.0

++++++ 0024-ucm-docs-fix-doxygen-exclude-patch-for-UCM-local-hea.patch ++++++
>From f66c7cc293b13765ffd67f530008e836f8354b13 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Mon, 29 Jun 2015 16:25:57 +0100
Subject: [PATCH 24/49] ucm: docs: fix doxygen exclude patch for UCM local
 header

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 doc/doxygen.cfg.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
index f4499d610290..043e75b2d7eb 100644
--- a/doc/doxygen.cfg.in
+++ b/doc/doxygen.cfg.in
@@ -94,7 +94,7 @@ EXCLUDE                = 
@top_srcdir@/src/control/control_local.h \
                   @top_srcdir@/src/mixer/mixer_local.h \
                   @top_srcdir@/src/rawmidi/rawmidi_local.h \
                   @top_srcdir@/src/seq/seq_local.h \
-                  @top_srcdir@/src/seq/ucm_local.h
+                  @top_srcdir@/src/ucm/ucm_local.h
 RECURSIVE       = YES
 FILE_PATTERNS    = *.c *.h
 EXAMPLE_PATH     = @top_srcdir@/test
-- 
2.5.0

++++++ 0025-ucm-docs-Fix-doxygen-formatting-for-UCM-main-page.patch ++++++
>From bb92545e064c3e2549878a328277eebe343aae61 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Mon, 29 Jun 2015 16:25:58 +0100
Subject: [PATCH 25/49] ucm: docs: Fix doxygen formatting for UCM main page.

Make sure group is defined and lists dipplayed correctly.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/use-case.h | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/include/use-case.h b/include/use-case.h
index c7789c03c4e8..9aac6e2fb51d 100644
--- a/include/use-case.h
+++ b/include/use-case.h
@@ -43,15 +43,13 @@ extern "C" {
 #endif
 
 /**
- *  \defgroup Use Case Interface
+ *  \defgroup ucm Use Case Interface
  *  The ALSA Use Case manager interface.
  *  See \ref Usecase page for more details.
  *  \{
  */
 
 /*! \page Usecase ALSA Use Case Interface
- * 
- * ALSA Use Case Interface
  *
  * The use case manager works by configuring the sound card ALSA kcontrols to
  * change the hardware digital and analog audio routing to match the requested
@@ -69,9 +67,9 @@ extern "C" {
  *
  * However there are times when a use case has to be modified at runtime. e.g.
  *
- *  o Incoming phone call when the device is playing music
- *  o Recording sections of a phone call
- *  o Playing tones during a call.
+ *  + Incoming phone call when the device is playing music
+ *  + Recording sections of a phone call
+ *  + Playing tones during a call.
  *
  * In order to allow asynchronous runtime use case adaptations, we have a third
  * optional modifier parameter that can be used to further configure
@@ -79,13 +77,13 @@ extern "C" {
  *
  * This interface allows clients to :-
  *
- *  o Query the supported use case verbs, devices and modifiers for the 
machine.
- *  o Set and Get use case verbs, devices and modifiers for the machine.
- *  o Get the ALSA PCM playback and capture device PCMs for use case verb,
+ *  + Query the supported use case verbs, devices and modifiers for the 
machine.
+ *  + Set and Get use case verbs, devices and modifiers for the machine.
+ *  + Get the ALSA PCM playback and capture device PCMs for use case verb,
  *     use case device and modifier.
- *  o Get the TQ parameter for each use case verb, use case device and
+ *  + Get the TQ parameter for each use case verb, use case device and
  *     modifier.
- *  o Get the ALSA master playback and capture volume/switch kcontrols
+ *  + Get the ALSA master playback and capture volume/switch kcontrols
  *     for each use case.
  */
 
-- 
2.5.0

++++++ 0026-docs-Add-UCM-link-to-main-doxygen-page.patch ++++++
>From c6df8273746645b2c5109537b07af6ed33d268d1 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Mon, 29 Jun 2015 16:25:59 +0100
Subject: [PATCH 26/49] docs: Add UCM link to main doxygen page.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 doc/index.doxygen | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/index.doxygen b/doc/index.doxygen
index 45aa68a11caa..7d049fe5c32a 100644
--- a/doc/index.doxygen
+++ b/doc/index.doxygen
@@ -40,6 +40,7 @@ may be placed in the library code instead of the kernel 
driver.</P>
   <LI>Page \ref rawmidi explains the design of the RawMidi API.
   <LI>Page \ref timer explains the design of the Timer API.
   <LI>Page \ref seq explains the design of the Sequencer API.
+  <LI>Page \ref ucm explains the use case API.
 </UL>
 
 <H2>Configuration</H2>
-- 
2.5.0

++++++ 0027-Replace-unsafe-characters-with-_-in-card-name.patch ++++++
>From 4dc44bb34aab2b23ab45c8e61e4b17bf2cf58959 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <[email protected]>
Date: Mon, 29 Jun 2015 22:53:53 +0500
Subject: [PATCH 27/49] Replace unsafe characters with _ in card name

Otherwise, they get misinterpreted as argument separators
in USB-Audio PCM definitions, and thus prevent SPDIF blacklist entries
from working.

While at it, add my Logitec C910 webcam to the SPDIF blacklist.

Signed-off-by: Alexander E. Patrakov <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/conf.h                |  1 +
 src/conf.c                    | 32 ++++++++++++++++++++++++++++++++
 src/conf/cards/USB-Audio.conf |  3 ++-
 src/confmisc.c                |  2 +-
 4 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/include/conf.h b/include/conf.h
index ff270f617383..087c05dc6bcf 100644
--- a/include/conf.h
+++ b/include/conf.h
@@ -126,6 +126,7 @@ int snd_config_imake_integer(snd_config_t **config, const 
char *key, const long
 int snd_config_imake_integer64(snd_config_t **config, const char *key, const 
long long value);
 int snd_config_imake_real(snd_config_t **config, const char *key, const double 
value);
 int snd_config_imake_string(snd_config_t **config, const char *key, const char 
*ascii);
+int snd_config_imake_safe_string(snd_config_t **config, const char *key, const 
char *ascii);
 int snd_config_imake_pointer(snd_config_t **config, const char *key, const 
void *ptr);
 
 snd_config_type_t snd_config_get_type(const snd_config_t *config);
diff --git a/src/conf.c b/src/conf.c
index bb256e7ae443..c6a83eef7d2f 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -2228,6 +2228,38 @@ int snd_config_imake_string(snd_config_t **config, const 
char *id, const char *v
        return 0;
 }
 
+int snd_config_imake_safe_string(snd_config_t **config, const char *id, const 
char *value)
+{
+       int err;
+       snd_config_t *tmp;
+       char *c;
+
+       err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
+       if (err < 0)
+               return err;
+       if (value) {
+               tmp->u.string = strdup(value);
+               if (!tmp->u.string) {
+                       snd_config_delete(tmp);
+                       return -ENOMEM;
+               }
+
+               for (c = tmp->u.string; *c; c++) {
+                       if (*c == ' ' || *c == '-' || *c == '_' ||
+                               (*c >= '0' && *c <= '9') ||
+                               (*c >= 'a' && *c <= 'z') ||
+                               (*c >= 'A' && *c <= 'Z'))
+                                       continue;
+                       *c = '_';
+               }
+       } else {
+               tmp->u.string = NULL;
+       }
+       *config = tmp;
+       return 0;
+}
+
+
 /**
  * \brief Creates a pointer configuration node with the given initial value.
  * \param[out] config The function puts the handle to the new node at
diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf
index 031bee0d86fd..e365f2979e6a 100644
--- a/src/conf/cards/USB-Audio.conf
+++ b/src/conf/cards/USB-Audio.conf
@@ -57,7 +57,8 @@ USB-Audio.pcm.iec958_device {
        "Scarlett 2i4 USB" 999
        "Sennheiser USB headset" 999
        "SWTOR Gaming Headset by Razer" 999
-       "USB Device 0x46d:0x992" 999
+       "USB Device 0x46d_0x821" 999
+       "USB Device 0x46d_0x992" 999
 }
 
 # Second iec958 device number, if any.
diff --git a/src/confmisc.c b/src/confmisc.c
index 1fb4f282217e..ae0275ff4de3 100644
--- a/src/confmisc.c
+++ b/src/confmisc.c
@@ -935,7 +935,7 @@ int snd_func_card_name(snd_config_t **dst, snd_config_t 
*root,
        }
        err = snd_config_get_id(src, &id);
        if (err >= 0)
-               err = snd_config_imake_string(dst, id,
+               err = snd_config_imake_safe_string(dst, id,
                                              snd_ctl_card_info_get_name(info));
       __error:
        if (ctl)
-- 
2.5.0

++++++ 0028-pcm-add-helper-functions-to-query-timestamping-capab.patch ++++++
>From 6cb31b444442f8ebca939cd78b80993f2ac85350 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <[email protected]>
Date: Wed, 1 Jul 2015 15:40:54 -0500
Subject: [PATCH 28/49] pcm: add helper functions to query timestamping
 capabilities

extend support to link, link_estimated and link_synchronized
timestamp. wall-clock is deprecated

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/pcm.h |  3 ++-
 src/pcm/pcm.c | 35 ++++++++++++++++++++++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/include/pcm.h b/include/pcm.h
index 0655e7f43ef6..2aa1eff36be3 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -668,7 +668,8 @@ int snd_pcm_hw_params_is_half_duplex(const 
snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t 
*params);
-int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t 
*params);
+int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t 
*params); /* deprecated, use audio_ts_type */
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t 
*params, int type);
 int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
                                      unsigned int *rate_num,
                                      unsigned int *rate_den);
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index bc18954b92da..846d502a6cb1 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -3190,12 +3190,45 @@ int snd_pcm_hw_params_can_disable_period_wakeup(const 
snd_pcm_hw_params_t *param
  */
 int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t 
*params)
 {
+       /* deprecated */
+       return snd_pcm_hw_params_supports_audio_ts_type(params,
+                                                       
SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT);
+}
+
+/**
+ * \brief Check if hardware supports type of audio timestamps
+ * \param params Configuration space
+ * \param type   Audio timestamp type
+ * \retval 0 Hardware doesn't support type of audio timestamps
+ * \retval 1 Hardware supports type of audio timestamps
+ *
+ * This function should only be called when the configuration space
+ * contains a single configuration. Call #snd_pcm_hw_params to choose
+ * a single configuration from the configuration space.
+ */
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t 
*params, int type)
+{
        assert(params);
        if (CHECK_SANITY(params->info == ~0U)) {
                SNDMSG("invalid PCM info field");
                return 0; /* FIXME: should be a negative error? */
        }
-       return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK);
+       switch (type) {
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT:
+               return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK); /* 
deprecated */
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT:
+               return 1; /* always supported, based on hw_ptr */
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK:
+               return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ATIME);
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE:
+               return !!(params->info & 
SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME);
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED:
+               return !!(params->info & 
SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME);
+       case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED:
+               return !!(params->info & 
SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME);
+       default:
+               return 0;
+       }
 }
 
 /**
-- 
2.5.0

++++++ 0029-pcm-add-support-for-get-set_audio_htstamp_config.patch ++++++
>From 6ec2464f397ff401c251057499abea77fd80b60b Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <[email protected]>
Date: Wed, 1 Jul 2015 15:40:55 -0500
Subject: [PATCH 29/49] pcm: add support for get/set_audio_htstamp_config

Enable kernel-side functionality by letting user select what sort of
timestamp it desires

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/pcm.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
 src/pcm/pcm.c | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/include/pcm.h b/include/pcm.h
index 2aa1eff36be3..a1d14a989a47 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -330,6 +330,26 @@ typedef enum _snd_pcm_tstamp_type {
        SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
 } snd_pcm_tstamp_type_t;
 
+typedef struct _snd_pcm_audio_tstamp_config {
+       /* 5 of max 16 bits used */
+       unsigned int type_requested:4;
+       unsigned int report_delay:1; /* add total delay to A/D or D/A */
+} snd_pcm_audio_tstamp_config_t;
+
+typedef struct _snd_pcm_audio_tstamp_report {
+       /* 6 of max 16 bits used for bit-fields */
+
+       /* for backwards compatibility */
+       unsigned int valid:1;
+
+       /* actual type if hardware could not support requested timestamp */
+       unsigned int actual_type:4;
+
+       /* accuracy represented in ns units */
+       unsigned int accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy 
field is valid */
+       unsigned int accuracy; /* up to 4.29s, will be packed in separate field 
 */
+} snd_pcm_audio_tstamp_report_t;
+
 /** Unsigned frames quantity */
 typedef unsigned long snd_pcm_uframes_t;
 /** Signed frames quantity */
@@ -981,6 +1001,30 @@ void snd_pcm_status_get_trigger_htstamp(const 
snd_pcm_status_t *obj, snd_htimest
 void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t 
*ptr);
 void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t 
*ptr);
 void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, 
snd_htimestamp_t *ptr);
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, 
snd_htimestamp_t *ptr);
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
+                                            snd_pcm_audio_tstamp_report_t 
*audio_tstamp_report);
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
+                                            snd_pcm_audio_tstamp_config_t 
*audio_tstamp_config);
+
+static inline void snd_pcm_pack_audio_tstamp_config(unsigned int *data,
+                                               snd_pcm_audio_tstamp_config_t 
*config)
+{
+       *data = config->report_delay;
+       *data <<= 4;
+       *data |= config->type_requested;
+}
+
+static inline void snd_pcm_unpack_audio_tstamp_report(unsigned int data, 
unsigned int accuracy,
+                                               snd_pcm_audio_tstamp_report_t 
*report)
+{
+       data >>= 16;
+       report->valid = data & 1;
+       report->actual_type = (data >> 1) & 0xF;
+       report->accuracy_report = (data >> 5) & 1;
+       report->accuracy = accuracy;
+}
+
 snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj);
 snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj);
 snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj);
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 846d502a6cb1..bae1d1653904 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -6367,6 +6367,44 @@ void snd_pcm_status_get_audio_htstamp(const 
snd_pcm_status_t *obj, snd_htimestam
 }
 
 /**
+ * \brief Get "now" hi-res driver timestamp from a PCM status container. 
Defines when the status
+ * was generated by driver, may differ from normal timestamp.
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to returned timestamp
+ */
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, 
snd_htimestamp_t *ptr)
+{
+       assert(obj && ptr);
+       *ptr = obj->driver_tstamp;
+}
+
+/**
+ * \brief Get audio_tstamp_report from a PCM status container
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to returned report (valid fields are accuracy and type)
+ */
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
+                                            snd_pcm_audio_tstamp_report_t 
*audio_tstamp_report)
+{
+       assert(obj && audio_tstamp_report);
+       snd_pcm_unpack_audio_tstamp_report(obj->audio_tstamp_data,
+                                       obj->audio_tstamp_accuracy,
+                                       audio_tstamp_report);
+}
+
+/**
+ * \brief set audio_tstamp_config from a PCM status container
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to config (valid fields are type and report_analog_delay)
+ */
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
+                                            snd_pcm_audio_tstamp_config_t 
*audio_tstamp_config)
+{
+       assert(obj && audio_tstamp_config);
+       snd_pcm_pack_audio_tstamp_config(&obj->audio_tstamp_data, 
audio_tstamp_config);
+}
+
+/**
  * \brief Get delay from a PCM status container (see #snd_pcm_delay)
  * \return Delay in frames
  *
-- 
2.5.0

++++++ 0030-pcm-add-support-for-new-STATUS_EXT-ioctl.patch ++++++
>From cc8b73436a90c35beda64bfa13b2196df20cfd81 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <[email protected]>
Date: Wed, 1 Jul 2015 15:40:56 -0500
Subject: [PATCH 30/49] pcm: add support for new STATUS_EXT ioctl

use STATUS_EXT ioctl if PCM protocol is > 2.0.12
All audio timestamp configuration will be ignored with an
older protocol.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/pcm/pcm_hw.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index c34b766ee035..232b19736db9 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -510,10 +510,18 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, 
snd_pcm_status_t * status)
 {
        snd_pcm_hw_t *hw = pcm->private_data;
        int fd = hw->fd, err;
-       if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
-               err = -errno;
-               SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
-               return err;
+       if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) {
+               if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
+                       err = -errno;
+                       SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
+                       return err;
+               }
+       } else {
+               if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) {
+                       err = -errno;
+                       SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err);
+                       return err;
+               }
        }
        if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
                status->tstamp.tv_nsec *= 1000L;
-- 
2.5.0

++++++ 0031-test-fix-audio_time-with-new-get-set-audio_tstamp_co.patch ++++++
>From 7bb3a74c4dbcfb01b0b91d94452d994b845b4ff3 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <[email protected]>
Date: Wed, 1 Jul 2015 15:40:57 -0500
Subject: [PATCH 31/49] test: fix audio_time with new get/set
 audio_tstamp_config

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 test/audio_time.c | 491 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 313 insertions(+), 178 deletions(-)

diff --git a/test/audio_time.c b/test/audio_time.c
index 7435db6a7fd8..e369e59b4ff2 100644
--- a/test/audio_time.c
+++ b/test/audio_time.c
@@ -4,13 +4,39 @@
  * helpful to verify the information reported by drivers.
  */
 
-#include "../include/asoundlib.h"
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <locale.h>
 #include <math.h>
+#include "../include/asoundlib.h"
 
-static char *device = "hw:0,0";
-
+static char *command;
+static char *pcm_name = "hw:0";
 snd_output_t *output = NULL;
 
+static void usage(char *command)
+{
+       printf("Usage: %s [OPTION]... \n"
+               "\n"
+               "-h, --help              help\n"
+               "-c, --capture           capture tstamps \n"
+               "-d, --delay             add delay \n"
+               "-D, --device=NAME       select PCM by name \n"
+               "-p, --playback          playback tstamps \n"
+               "-t, --ts_type=TYPE      
Default(0),link(1),link_estimated(2),synchronized(3) \n"
+               , command);
+}
+
+
 long long timestamp2ns(snd_htimestamp_t t)
 {
        long long nsec;
@@ -31,15 +57,20 @@ long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
        return nsec1 - nsec2;
 }
 
-void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
-                 snd_htimestamp_t *trigger_timestamp,
-                 snd_htimestamp_t *audio_timestamp,
-                 snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
+void _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
+                  snd_htimestamp_t *trigger_timestamp,
+                  snd_htimestamp_t *audio_timestamp,
+                  snd_pcm_audio_tstamp_config_t  *audio_tstamp_config,
+                  snd_pcm_audio_tstamp_report_t  *audio_tstamp_report,
+                  snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
 {
        int err;
        snd_pcm_status_t *status;
 
        snd_pcm_status_alloca(&status);
+
+       snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config);
+
        if ((err = snd_pcm_status(handle, status)) < 0) {
                printf("Stream status error: %s\n", snd_strerror(err));
                exit(0);
@@ -47,26 +78,30 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t 
*timestamp,
        snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
        snd_pcm_status_get_htstamp(status, timestamp);
        snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
+       snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report);
        *avail = snd_pcm_status_get_avail(status);
        *delay = snd_pcm_status_get_delay(status);
 }
 
-#define PERIOD 6000
+#define TIMESTAMP_FREQ 8 /* Hz */
+#define SAMPLE_FREQ 48000
+#define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ)
 #define PCM_LINK        /* sync start for playback and capture */
 #define TRACK_CAPTURE   /* dump capture timing info  */
 #define TRACK_PLAYBACK  /* dump playback timing info */
-#define TRACK_SAMPLE_COUNTS /* show difference between sample counters and 
audiotimestamps returned by driver */
+/*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters 
and audiotimestamps returned by driver */
 #define PLAYBACK_BUFFERS 4
-#define TSTAMP_TYPE    SND_PCM_TSTAMP_TYPE_MONOTONIC
+#define TSTAMP_TYPE    SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW
 
 
-int main(void)
+int main(int argc, char *argv[])
 {
-        int err;
-        unsigned int i;
-        snd_pcm_t *handle_p = NULL;
-        snd_pcm_t *handle_c = NULL;
-        snd_pcm_sframes_t frames;
+       int c;
+       int err;
+       unsigned int i;
+       snd_pcm_t *handle_p = NULL;
+       snd_pcm_t *handle_c = NULL;
+       snd_pcm_sframes_t frames;
        snd_htimestamp_t tstamp_c, tstamp_p;
        snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
        snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
@@ -87,206 +122,306 @@ int main(void)
        snd_pcm_sframes_t delay_p, delay_c;
        snd_pcm_uframes_t avail_p, avail_c;
 
-       if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) 
< 0) {
-               printf("Playback open error: %s\n", snd_strerror(err));
-               goto _exit;
-       }
-       if ((err = snd_pcm_set_params(handle_p,
-                                     SND_PCM_FORMAT_S16,
-                                     SND_PCM_ACCESS_RW_INTERLEAVED,
-                                     2,
-                                     48000,
-                                     0,
-                                     500000)) < 0) {   /* 0.5sec */
-               printf("Playback open error: %s\n", snd_strerror(err));
-               goto _exit;
+       snd_pcm_audio_tstamp_config_t audio_tstamp_config_p;
+       snd_pcm_audio_tstamp_config_t audio_tstamp_config_c;
+       snd_pcm_audio_tstamp_report_t audio_tstamp_report_p;
+       snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
+
+       int option_index;
+       static const char short_options[] = "hcpdD:t:";
+
+       static const struct option long_options[] = {
+               {"capture", 0, 0, 'c'},
+               {"delay", 0, 0, 'd'},
+               {"device", required_argument, 0, 'D'},
+               {"help", no_argument, 0, 'h'},
+               {"playback", 0, 0, 'p'},
+               {"ts_type", required_argument, 0, 't'},
+               {0, 0, 0, 0}
+       };
+
+       int do_delay = 0;
+       int do_playback = 0;
+       int do_capture = 0;
+       int type = 0;
+
+       while ((c = getopt_long(argc, argv, short_options, long_options, 
&option_index)) != -1) {
+               switch (c) {
+               case 'h':
+                       usage(command);
+                       return 0;
+               case 'p':
+                       do_playback = 1;
+                       break;
+               case 'c':
+                       do_capture = 1;
+                       break;
+               case 'd':
+                       do_delay = 1;
+                       break;
+               case 'D':
+                       pcm_name = optarg;
+                       break;
+               case 't':
+                       type = atoi(optarg);
+                       break;
+               }
        }
 
-       snd_pcm_hw_params_alloca(&hwparams_p);
-       /* get the current hwparams */
-       err = snd_pcm_hw_params_current(handle_p, hwparams_p);
-       if (err < 0) {
-               printf("Unable to determine current hwparams_p: %s\n", 
snd_strerror(err));
-               goto _exit;
-       }
-       if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_p))
-               printf("Playback relies on audio wallclock timestamps\n");
-       else
-               printf("Playback relies on audio sample counter timestamps\n");
-
-       snd_pcm_sw_params_alloca(&swparams_p);
-       /* get the current swparams */
-       err = snd_pcm_sw_params_current(handle_p, swparams_p);
-       if (err < 0) {
-               printf("Unable to determine current swparams_p: %s\n", 
snd_strerror(err));
-               goto _exit;
-       }
+       memset(&audio_tstamp_config_p, 0, 
sizeof(snd_pcm_audio_tstamp_config_t));
+       memset(&audio_tstamp_config_c, 0, 
sizeof(snd_pcm_audio_tstamp_config_t));
+       memset(&audio_tstamp_report_p, 0, 
sizeof(snd_pcm_audio_tstamp_report_t));
+       memset(&audio_tstamp_report_c, 0, 
sizeof(snd_pcm_audio_tstamp_report_t));
 
-       /* enable tstamp */
-       err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, 
SND_PCM_TSTAMP_ENABLE);
-       if (err < 0) {
-               printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
-               goto _exit;
-       }
+       if (do_playback) {
+               if ((err = snd_pcm_open(&handle_p, pcm_name, 
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+                       printf("Playback open error: %s\n", snd_strerror(err));
+                       goto _exit;
+               }
 
-       err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, 
TSTAMP_TYPE);
-       if (err < 0) {
-               printf("Unable to set tstamp type : %s\n", snd_strerror(err));
-               goto _exit;
-       }
+               if ((err = snd_pcm_set_params(handle_p,
+                                                       SND_PCM_FORMAT_S16,
+                                                       
SND_PCM_ACCESS_RW_INTERLEAVED,
+                                                       2,
+                                                       SAMPLE_FREQ,
+                                                       0,
+                                                       
4*1000000/TIMESTAMP_FREQ)) < 0) {
+                       printf("Playback open error: %s\n", snd_strerror(err));
+                       goto _exit;
+               }
 
-       /* write the sw parameters */
-       err = snd_pcm_sw_params(handle_p, swparams_p);
-       if (err < 0) {
-               printf("Unable to set swparams_p : %s\n", snd_strerror(err));
-               goto _exit;
-       }
+               snd_pcm_hw_params_alloca(&hwparams_p);
+/* get the current hwparams */
+               err = snd_pcm_hw_params_current(handle_p, hwparams_p);
+               if (err < 0) {
+                       printf("Unable to determine current hwparams_p: %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
 
-       if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, 
SND_PCM_NONBLOCK)) < 0) {
-               printf("Capture open error: %s\n", snd_strerror(err));
-               goto _exit;
-       }
-       if ((err = snd_pcm_set_params(handle_c,
-                                     SND_PCM_FORMAT_S16,
-                                     SND_PCM_ACCESS_RW_INTERLEAVED,
-                                     2,
-                                     48000,
-                                     0,
-                                     500000)) < 0) {   /* 0.5sec */
-               printf("Capture open error: %s\n", snd_strerror(err));
-               goto _exit;
-       }
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0))
+                       printf("Playback supports audio compat timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1))
+                       printf("Playback supports audio default timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2))
+                       printf("Playback supports audio link timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3))
+                       printf("Playback supports audio link absolute 
timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4))
+                       printf("Playback supports audio link estimated 
timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5))
+                       printf("Playback supports audio link synchronized 
timestamps\n");
+
+               snd_pcm_sw_params_alloca(&swparams_p);
+               /* get the current swparams */
+               err = snd_pcm_sw_params_current(handle_p, swparams_p);
+               if (err < 0) {
+                       printf("Unable to determine current swparams_p: %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
 
-       snd_pcm_hw_params_alloca(&hwparams_c);
-       /* get the current hwparams */
-       err = snd_pcm_hw_params_current(handle_c, hwparams_c);
-       if (err < 0) {
-               printf("Unable to determine current hwparams_c: %s\n", 
snd_strerror(err));
-               goto _exit;
-       }
-       if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_c))
-               printf("Capture relies on audio wallclock timestamps\n");
-       else
-               printf("Capture relies on audio sample counter timestamps\n");
-
-       snd_pcm_sw_params_alloca(&swparams_c);
-       /* get the current swparams */
-       err = snd_pcm_sw_params_current(handle_c, swparams_c);
-       if (err < 0) {
-               printf("Unable to determine current swparams_c: %s\n", 
snd_strerror(err));
-               goto _exit;
-       }
+               /* enable tstamp */
+               err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, 
SND_PCM_TSTAMP_ENABLE);
+               if (err < 0) {
+                       printf("Unable to set tstamp mode : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
 
-       /* enable tstamp */
-       err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, 
SND_PCM_TSTAMP_ENABLE);
-       if (err < 0) {
-               printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
-               goto _exit;
-       }
+               err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, 
TSTAMP_TYPE);
+               if (err < 0) {
+                       printf("Unable to set tstamp type : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
+
+               /* write the sw parameters */
+               err = snd_pcm_sw_params(handle_p, swparams_p);
+               if (err < 0) {
+                       printf("Unable to set swparams_p : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
 
-       err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, 
TSTAMP_TYPE);
-       if (err < 0) {
-               printf("Unable to set tstamp type : %s\n", snd_strerror(err));
-               goto _exit;
        }
 
-       /* write the sw parameters */
-       err = snd_pcm_sw_params(handle_c, swparams_c);
-       if (err < 0) {
-               printf("Unable to set swparams_c : %s\n", snd_strerror(err));
-               goto _exit;
+       if (do_capture) {
+
+               if ((err = snd_pcm_open(&handle_c, pcm_name, 
SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+                       printf("Capture open error: %s\n", snd_strerror(err));
+                       goto _exit;
+               }
+               if ((err = snd_pcm_set_params(handle_c,
+                                                       SND_PCM_FORMAT_S16,
+                                                       
SND_PCM_ACCESS_RW_INTERLEAVED,
+                                                       2,
+                                                       SAMPLE_FREQ,
+                                                       0,
+                                                       
4*1000000/TIMESTAMP_FREQ)) < 0) {
+                       printf("Capture open error: %s\n", snd_strerror(err));
+                       goto _exit;
+               }
+
+               snd_pcm_hw_params_alloca(&hwparams_c);
+               /* get the current hwparams */
+               err = snd_pcm_hw_params_current(handle_c, hwparams_c);
+               if (err < 0) {
+                       printf("Unable to determine current hwparams_c: %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
+
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0))
+                       printf("Capture supports audio compat timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1))
+                       printf("Capture supports audio default timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2))
+                       printf("Capture supports audio link timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3))
+                       printf("Capture supports audio link absolute 
timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4))
+                       printf("Capture supports audio link estimated 
timestamps\n");
+               if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5))
+                       printf("Capture supports audio link synchronized 
timestamps\n");
+
+               snd_pcm_sw_params_alloca(&swparams_c);
+               /* get the current swparams */
+               err = snd_pcm_sw_params_current(handle_c, swparams_c);
+               if (err < 0) {
+                       printf("Unable to determine current swparams_c: %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
+
+               /* enable tstamp */
+               err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, 
SND_PCM_TSTAMP_ENABLE);
+               if (err < 0) {
+                       printf("Unable to set tstamp mode : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
+
+               err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, 
TSTAMP_TYPE);
+               if (err < 0) {
+                       printf("Unable to set tstamp type : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
+
+               /* write the sw parameters */
+               err = snd_pcm_sw_params(handle_c, swparams_c);
+               if (err < 0) {
+                       printf("Unable to set swparams_c : %s\n", 
snd_strerror(err));
+                       goto _exit;
+               }
        }
 
+       if (do_playback && do_capture) {
 #ifdef PCM_LINK
-       if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
-               printf("Streams link error: %s\n", snd_strerror(err));
-               exit(0);
-       }
+               if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
+                       printf("Streams link error: %s\n", snd_strerror(err));
+                       exit(0);
+               }
 #endif
-
-       i = PLAYBACK_BUFFERS;
-       while (i--) {
-                frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_writei failed: %s\n", 
snd_strerror(frames));
-                        goto _exit;
-                }
-               frame_count_p += frames;
        }
 
-       if (PLAYBACK_BUFFERS != 4)
-               snd_pcm_start(handle_p);
+       if (do_playback) {
+               i = PLAYBACK_BUFFERS;
+               while (i--) {
+                       frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+                       if (frames < 0) {
+                               printf("snd_pcm_writei failed: %s\n", 
snd_strerror(frames));
+                               goto _exit;
+                       }
+                       frame_count_p += frames;
+               }
+
+               if (PLAYBACK_BUFFERS != 4)
+                       snd_pcm_start(handle_p);
+       }
 
+       if (do_capture) {
 #ifndef PCM_LINK
-       /* need to start capture explicitly */
-       snd_pcm_start(handle_c);
+               /* need to start capture explicitly */
+               snd_pcm_start(handle_c);
+#else
+               if (!do_playback)
+                       /* need to start capture explicitly */
+                       snd_pcm_start(handle_c);
 #endif
+       }
 
-        while (1) {
-
-               frames = snd_pcm_wait(handle_c, -1);
-               if (frames < 0) {
-                       printf("snd_pcm_wait failed: %s\n", 
snd_strerror(frames));
-                        goto _exit;
-               }
-
-               frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_readi failed: %s\n", 
snd_strerror(frames));
-                        goto _exit;
-                }
-               frame_count_c += frames;
+       while (1) {
 
-                frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_writei failed: %s\n", 
snd_strerror(frames));
-                        goto _exit;
-                }
+               if (do_capture) {
 
-               frame_count_p += frames;
+                       frames = snd_pcm_wait(handle_c, -1);
+                       if (frames < 0) {
+                               printf("snd_pcm_wait failed: %s\n", 
snd_strerror(frames));
+                               goto _exit;
+                       }
 
-#if defined(TRACK_PLAYBACK)
-               gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, 
&audio_tstamp_p, &avail_p, &delay_p);
+                       frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
+                       if (frames < 0) {
+                               printf("snd_pcm_readi failed: %s\n", 
snd_strerror(frames));
+                               goto _exit;
+                       }
+                       frame_count_c += frames;
 
+#if defined(TRACK_CAPTURE)
+                       audio_tstamp_config_c.type_requested = type;
+                       audio_tstamp_config_c.report_delay = do_delay;
+                       _gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c,
+                               &audio_tstamp_c, &audio_tstamp_config_c, 
&audio_tstamp_report_c,
+                               &avail_c, &delay_c);
 #if defined(TRACK_SAMPLE_COUNTS)
-               curr_count_p = frame_count_p - delay_p; /* written minus queued 
*/
+                       curr_count_c = frame_count_c + delay_c; /* read plus 
queued */
 
-               printf("playback: curr_count %lli driver count %lli, delta 
%lli\n",
-                      (long long)curr_count_p * 1000000000LL / 48000 ,
-                      timestamp2ns(audio_tstamp_p),
-                      (long long)curr_count_p * 1000000000LL / 48000 - 
timestamp2ns(audio_tstamp_p)
-                      );
+
+                       printf("capture: curr_count %lli driver count %lli, 
delta %lli\n",
+                               (long long)curr_count_c * 1000000000LL / 
SAMPLE_FREQ ,
+                               timestamp2ns(audio_tstamp_c),
+                               (long long)curr_count_c * 1000000000LL / 
SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
+                               );
 #endif
 
-               printf("playback: systime: %lli nsec, audio time %lli nsec, 
\tsystime delta %lli\n",
-                      timediff(tstamp_p, trigger_tstamp_p),
-                      timestamp2ns(audio_tstamp_p),
-                      timediff(tstamp_p, trigger_tstamp_p) - 
timestamp2ns(audio_tstamp_p)
-                      );
+                       printf("\t capture: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli\n",
+                               timediff(tstamp_c, trigger_tstamp_c),
+                               timestamp2ns(audio_tstamp_c),
+                               timediff(tstamp_c, trigger_tstamp_c) - 
timestamp2ns(audio_tstamp_c)
+                               );
 #endif
+               }
 
-#if defined(TRACK_CAPTURE)
-               gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, 
&audio_tstamp_c, &avail_c, &delay_c);
+               if (do_playback) {
+                       frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+                       if (frames < 0) {
+                               printf("snd_pcm_writei failed: %s\n", 
snd_strerror(frames));
+                               goto _exit;
+                       }
 
-#if defined(TRACK_SAMPLE_COUNTS)
-               curr_count_c = frame_count_c + delay_c; /* read plus queued */
+                       frame_count_p += frames;
+
+#if defined(TRACK_PLAYBACK)
 
+                       audio_tstamp_config_p.type_requested = type;
+                       audio_tstamp_config_p.report_delay = do_delay;
+                       _gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p,
+                               &audio_tstamp_p, &audio_tstamp_config_p, 
&audio_tstamp_report_p,
+                               &avail_p, &delay_p);
 
-               printf("capture: curr_count %lli driver count %lli, delta 
%lli\n",
-                      (long long)curr_count_c * 1000000000LL / 48000 ,
-                      timestamp2ns(audio_tstamp_c),
-                      (long long)curr_count_c * 1000000000LL / 48000 - 
timestamp2ns(audio_tstamp_c)
-                      );
+#if defined(TRACK_SAMPLE_COUNTS)
+                       curr_count_p = frame_count_p - delay_p; /* written 
minus queued */
+
+                       printf("playback: curr_count %lli driver count %lli, 
delta %lli\n",
+                               (long long)curr_count_p * 1000000000LL / 
SAMPLE_FREQ ,
+                               timestamp2ns(audio_tstamp_p),
+                               (long long)curr_count_p * 1000000000LL / 
SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
+                               );
 #endif
 
-               printf("\t capture: systime: %lli nsec, audio time %lli nsec, 
\tsystime delta %lli\n",
-                      timediff(tstamp_c, trigger_tstamp_c),
-                      timestamp2ns(audio_tstamp_c),
-                      timediff(tstamp_c, trigger_tstamp_c) - 
timestamp2ns(audio_tstamp_c)
-                      );
+                       printf("playback: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli\n",
+                               timediff(tstamp_p, trigger_tstamp_p),
+                               timestamp2ns(audio_tstamp_p),
+                               timediff(tstamp_p, trigger_tstamp_p) - 
timestamp2ns(audio_tstamp_p)
+                               );
 #endif
+               }
+
 
-        }
+       } /* while(1) */
 
 _exit:
        if (handle_p)
-- 
2.5.0

++++++ 0032-test-audio_time-show-report-validity-and-accuracy.patch ++++++
>From 6849d7dc88e0fe22cddb6b2d06ddc967ad4c3a6c Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <[email protected]>
Date: Wed, 1 Jul 2015 15:40:58 -0500
Subject: [PATCH 32/49] test: audio_time: show report validity and accuracy

Add checks to show if driver reports valid report and resolution
information. disabled by default

Signed-off-by: Pierre-Louis Bossart <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 test/audio_time.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/test/audio_time.c b/test/audio_time.c
index e369e59b4ff2..a54c10dc9ebd 100644
--- a/test/audio_time.c
+++ b/test/audio_time.c
@@ -33,6 +33,7 @@ static void usage(char *command)
                "-D, --device=NAME       select PCM by name \n"
                "-p, --playback          playback tstamps \n"
                "-t, --ts_type=TYPE      
Default(0),link(1),link_estimated(2),synchronized(3) \n"
+               "-r, --report            show audio timestamp and accuracy 
validity\n"
                , command);
 }
 
@@ -128,7 +129,7 @@ int main(int argc, char *argv[])
        snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
 
        int option_index;
-       static const char short_options[] = "hcpdD:t:";
+       static const char short_options[] = "hcpdrD:t:";
 
        static const struct option long_options[] = {
                {"capture", 0, 0, 'c'},
@@ -137,6 +138,7 @@ int main(int argc, char *argv[])
                {"help", no_argument, 0, 'h'},
                {"playback", 0, 0, 'p'},
                {"ts_type", required_argument, 0, 't'},
+               {"report", 0, 0, 'r'},
                {0, 0, 0, 0}
        };
 
@@ -144,6 +146,7 @@ int main(int argc, char *argv[])
        int do_playback = 0;
        int do_capture = 0;
        int type = 0;
+       int do_report = 0;
 
        while ((c = getopt_long(argc, argv, short_options, long_options, 
&option_index)) != -1) {
                switch (c) {
@@ -165,6 +168,8 @@ int main(int argc, char *argv[])
                case 't':
                        type = atoi(optarg);
                        break;
+               case 'r':
+                       do_report = 1;
                }
        }
 
@@ -376,11 +381,19 @@ int main(int argc, char *argv[])
                                (long long)curr_count_c * 1000000000LL / 
SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
                                );
 #endif
+                       if (do_report) {
+                               if (audio_tstamp_report_c.valid == 0)
+                                       printf("Audio capture timestamp report 
invalid - ");
+                               if (audio_tstamp_report_c.accuracy_report == 0)
+                                       printf("Audio capture timestamp 
accuracy report invalid");
+                               printf("\n");
+                       }
+
 
-                       printf("\t capture: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli\n",
+                       printf("\t capture: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli \t resolution %d ns \n", 
                                timediff(tstamp_c, trigger_tstamp_c),
                                timestamp2ns(audio_tstamp_c),
-                               timediff(tstamp_c, trigger_tstamp_c) - 
timestamp2ns(audio_tstamp_c)
+                               timediff(tstamp_c, trigger_tstamp_c) - 
timestamp2ns(audio_tstamp_c), audio_tstamp_report_c.accuracy
                                );
 #endif
                }
@@ -411,11 +424,18 @@ int main(int argc, char *argv[])
                                (long long)curr_count_p * 1000000000LL / 
SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
                                );
 #endif
+                       if (do_report) {
+                               if (audio_tstamp_report_p.valid == 0)
+                                       printf("Audio playback timestamp report 
invalid - ");
+                               if (audio_tstamp_report_p.accuracy_report == 0)
+                                       printf("Audio playback timestamp 
accuracy report invalid");
+                               printf("\n");
+                       }
 
-                       printf("playback: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli\n",
+                       printf("playback: systime: %lli nsec, audio time %lli 
nsec, \tsystime delta %lli resolution %d ns\n",
                                timediff(tstamp_p, trigger_tstamp_p),
                                timestamp2ns(audio_tstamp_p),
-                               timediff(tstamp_p, trigger_tstamp_p) - 
timestamp2ns(audio_tstamp_p)
+                               timediff(tstamp_p, trigger_tstamp_p) - 
timestamp2ns(audio_tstamp_p), audio_tstamp_report_p.accuracy
                                );
 #endif
                }
-- 
2.5.0

++++++ 0033-pcm-restore-hw-params-on-set-latency-failed.patch ++++++
>From 77b6be63876ee46a95320e77735d977edeedd44a Mon Sep 17 00:00:00 2001
From: Martin Geier <[email protected]>
Date: Fri, 24 Jul 2015 09:30:57 +0200
Subject: [PATCH 33/49] pcm: restore hw params on set latency failed

When method snd_pcm_set_params sets sample rate to 22050 and latency to 50000
to davinci soc driver method snd_pcm_hw_params_set_buffer_time_near fails
and variable params is already changed in the method so the next method
snd_pcm_hw_params_set_period_time_near fails also.

Signed-off-by: Martin Geier <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/pcm/pcm.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index bae1d1653904..f5fc728518d8 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -8004,7 +8004,7 @@ int snd_pcm_set_params(snd_pcm_t *pcm,
                        int soft_resample,
                        unsigned int latency)
 {
-        snd_pcm_hw_params_t *params;
+        snd_pcm_hw_params_t *params, params_saved;
         snd_pcm_sw_params_t *swparams;
         const char *s = snd_pcm_stream_name(snd_pcm_stream(pcm));
         snd_pcm_uframes_t buffer_size, period_size;
@@ -8057,9 +8057,11 @@ int snd_pcm_set_params(snd_pcm_t *pcm,
                return -EINVAL;
        }
        /* set the buffer time */
+       params_saved = *params;
        err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, params, 
&latency, NULL);
        if (err < 0) {
                /* error path -> set period size as first */
+               *params = params_saved;
                /* set the period time */
                period_time = latency / 4;
                err = INTERNAL(snd_pcm_hw_params_set_period_time_near)(pcm, 
params, &period_time, NULL);
-- 
2.5.0

++++++ 0034-Replace-list.h-with-its-own-version.patch ++++++
>From d0e13f87742e923edfb638d4b16b69b8dc2136d8 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <[email protected]>
Date: Mon, 27 Jul 2015 12:32:37 +0200
Subject: [PATCH 34/49] Replace list.h with its own version

We copied include/list.h from Linux kernel, and it's of course in
GPLv2.  This has raised concerns to many people, as it's not clear
whether such a code is considered to be completely trivial, thus it
might be seen as a derivative work, which takes effect in GPL, as
suggested by Clemens.

For clearing the situation, this patch replaces the existing list.h
implementation from a new version.  The API is kept to be compatible,
but the codes were written from full scratch under LGPL, to be aligned
with other alsa-lib codes.

Reported-by: Clemens Lang <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/list.h | 212 +++++++++++++++++++--------------------------------------
 1 file changed, 70 insertions(+), 142 deletions(-)

diff --git a/include/list.h b/include/list.h
index 4d9895feba05..947c1f8411e2 100644
--- a/include/list.h
+++ b/include/list.h
@@ -1,174 +1,102 @@
+/* Doubly linked list macros compatible with Linux kernel's version
+ * Copyright (c) 2015 by Takashi Iwai <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
 #ifndef _LIST_H
 #define _LIST_H
 
-/*
- * This code was taken from the Linux 2.4.0 kernel. [jaroslav]
- */
+#include <stddef.h>
 
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-#ifndef LIST_HEAD_IS_DEFINED
 struct list_head {
-       struct list_head *next, *prev;
+       struct list_head *next;
+       struct list_head *prev;
 };
-#endif
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
 
-#define LIST_HEAD(name) \
-       struct list_head name = LIST_HEAD_INIT(name)
+/* one-shot definition of a list head */
+#define LIST_HEAD(x) \
+       struct list_head x = { &x, &x }
 
-#define INIT_LIST_HEAD(ptr) do { \
-       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/*
- * Insert a new entry between two known consecutive entries. 
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static __inline__ void __list_add(struct list_head * _new,
-                                 struct list_head * prev,
-                                 struct list_head * next)
+/* initialize a list head explicitly */
+static inline void INIT_LIST_HEAD(struct list_head *p)
 {
-       next->prev = _new;
-       _new->next = next;
-       _new->prev = prev;
-       prev->next = _new;
+       p->next = p->prev = p;
 }
 
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
+#define list_entry_offset(p, type, offset) \
+       ((type *)((char *)(p) - (offset)))
+
+/* list_entry - retrieve the original struct from list_head
+ * @p: list_head pointer
+ * @type: struct type
+ * @member: struct field member containing the list_head
  */
-static __inline__ void list_add(struct list_head *_new, struct list_head *head)
-{
-       __list_add(_new, head, head->next);
-}
+#define list_entry(p, type, member) \
+       list_entry_offset(p, type, offsetof(type, member))
 
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
+/* list_for_each - iterate over the linked list
+ * @p: iterator, a list_head pointer variable
+ * @list: list_head pointer containing the list
  */
-static __inline__ void list_add_tail(struct list_head *_new, struct list_head 
*head)
-{
-       __list_add(_new, head->prev, head);
-}
+#define list_for_each(p, list) \
+       for (p = (list)->next; p != (list); p = p->next)
 
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
+/* list_for_each_safe - iterate over the linked list, safe to delete
+ * @p: iterator, a list_head pointer variable
+ * @s: a temporary variable to keep the next, a list_head pointer, too
+ * @list: list_head pointer containing the list
  */
-static __inline__ void __list_del(struct list_head * prev,
-                                 struct list_head * next)
-{
-       next->prev = prev;
-       prev->next = next;
-}
+#define list_for_each_safe(p, s, list) \
+       for (p = (list)->next; s = p->next, p != (list); p = s)
 
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is in 
an undefined state.
+/* list_add - prepend a list entry at the head
+ * @p: the new list entry to add
+ * @list: the list head
  */
-static __inline__ void list_del(struct list_head *entry)
+static inline void list_add(struct list_head *p, struct list_head *list)
 {
-       __list_del(entry->prev, entry->next);
+       struct list_head *first = list->next;
+
+       p->next = first;
+       first->prev = p;
+       list->next = p;
+       p->prev = list;
 }
 
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.n 
+/* list_add_tail - append a list entry at the tail
+ * @p: the new list entry to add
+ * @list: the list head
  */
-static __inline__ void list_del_init(struct list_head *entry)
+static inline void list_add_tail(struct list_head *p, struct list_head *list)
 {
-       __list_del(entry->prev, entry->next);
-       INIT_LIST_HEAD(entry); 
+       struct list_head *last = list->prev;
+
+       last->next = p;
+       p->prev = last;
+       p->next = list;
+       list->prev = p;
 }
 
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static __inline__ int list_empty(struct list_head *head)
+/* list_del - delete the given list entry */
+static inline void list_del(struct list_head *p)
 {
-       return head->next == head;
+       p->prev->next = p->next;
+       p->next->prev = p->prev;
 }
 
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static __inline__ void list_splice(struct list_head *list, struct list_head 
*head)
+/* list_empty - returns 1 if the given list is empty */
+static inline int list_empty(const struct list_head *p)
 {
-       struct list_head *first = list->next;
-
-       if (first != list) {
-               struct list_head *last = list->prev;
-               struct list_head *at = head->next;
-
-               first->prev = head;
-               head->next = first;
-
-               last->next = at;
-               at->prev = last;
-       }
+       return p->next == p;
 }
 
-/**
- * list_for_each       -       iterate over a list
- * @pos:       the &struct list_head to use as a loop counter.
- * @head:      the head for your list.
- */
-#define list_for_each(pos, head) \
-       for (pos = (head)->next ; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_safe  -       iterate over a list safely (actual pointer can 
be invalidated)
- * @pos:       the &struct list_head to use as a loop counter.
- * @next:      the &struct list_head to use to save next.
- * @head:      the head for your list.
- */
-#define list_for_each_safe(pos, npos, head) \
-       for (pos = (head)->next, npos = pos->next ; pos != (head); pos = npos, 
npos = pos->next)
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
-       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @offset:    offset of entry inside a struct
- */
-#define list_entry_offset(ptr, type, offset) \
-       ((type *)((char *)(ptr)-(offset)))
-
 #endif /* _LIST_H */
-- 
2.5.0

++++++ 0035-topology-uapi-Add-UAPI-headers-for-topology-ABI.patch ++++++
>From 227c790c16db17a986df06c9a3ad79edade78db7 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:13 +0100
Subject: [PATCH 35/49] topology: uapi: Add UAPI headers for topology ABI

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 include/sound/Makefile.am |   3 +-
 include/sound/asoc.h      | 388 ++++++++++++++++++++++++++++++++++++++++++++++
 include/sound/tlv.h       |  23 +++
 3 files changed, 413 insertions(+), 1 deletion(-)
 create mode 100644 include/sound/asoc.h
 create mode 100644 include/sound/tlv.h

diff --git a/include/sound/Makefile.am b/include/sound/Makefile.am
index 31aa2db43d27..b659985e7e36 100644
--- a/include/sound/Makefile.am
+++ b/include/sound/Makefile.am
@@ -1,6 +1,7 @@
 alsasoundincludedir = ${includedir}/alsa/sound
 
 alsasoundinclude_HEADERS = asound_fm.h hdsp.h hdspm.h sb16_csp.h \
-                          sscape_ioctl.h emu10k1.h type_compat.h
+                          sscape_ioctl.h emu10k1.h type_compat.h \
+                          asoc.h tlv.h
 
 noinst_HEADERS = asound.h asoundef.h asequencer.h
diff --git a/include/sound/asoc.h b/include/sound/asoc.h
new file mode 100644
index 000000000000..bb6dcf3ff7b4
--- /dev/null
+++ b/include/sound/asoc.h
@@ -0,0 +1,388 @@
+/*
+ * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
+ * algorithms, equalisers, DAIs, widgets etc.
+*/
+
+#ifndef __LINUX_UAPI_SND_ASOC_H
+#define __LINUX_UAPI_SND_ASOC_H
+
+/*
+ * Maximum number of channels topology kcontrol can represent.
+ */
+#define SND_SOC_TPLG_MAX_CHAN          8
+
+/*
+ * Maximum number of PCM formats capability
+ */
+#define SND_SOC_TPLG_MAX_FORMATS       16
+
+/*
+ * Maximum number of PCM stream configs
+ */
+#define SND_SOC_TPLG_STREAM_CONFIG_MAX  8
+
+/* individual kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_CTL_VOLSW         1
+#define SND_SOC_TPLG_CTL_VOLSW_SX      2
+#define SND_SOC_TPLG_CTL_VOLSW_XR_SX   3
+#define SND_SOC_TPLG_CTL_ENUM          4
+#define SND_SOC_TPLG_CTL_BYTES         5
+#define SND_SOC_TPLG_CTL_ENUM_VALUE    6
+#define SND_SOC_TPLG_CTL_RANGE         7
+#define SND_SOC_TPLG_CTL_STROBE                8
+
+
+/* individual widget kcontrol info types - can be mixed with other types */
+#define SND_SOC_TPLG_DAPM_CTL_VOLSW            64
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE      65
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT                66
+#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE       67
+#define SND_SOC_TPLG_DAPM_CTL_PIN              68
+
+/* DAPM widget types - add new items to the end */
+#define SND_SOC_TPLG_DAPM_INPUT                0
+#define SND_SOC_TPLG_DAPM_OUTPUT       1
+#define SND_SOC_TPLG_DAPM_MUX          2
+#define SND_SOC_TPLG_DAPM_MIXER                3
+#define SND_SOC_TPLG_DAPM_PGA          4
+#define SND_SOC_TPLG_DAPM_OUT_DRV      5
+#define SND_SOC_TPLG_DAPM_ADC          6
+#define SND_SOC_TPLG_DAPM_DAC          7
+#define SND_SOC_TPLG_DAPM_SWITCH       8
+#define SND_SOC_TPLG_DAPM_PRE          9
+#define SND_SOC_TPLG_DAPM_POST         10
+#define SND_SOC_TPLG_DAPM_AIF_IN       11
+#define SND_SOC_TPLG_DAPM_AIF_OUT      12
+#define SND_SOC_TPLG_DAPM_DAI_IN       13
+#define SND_SOC_TPLG_DAPM_DAI_OUT      14
+#define SND_SOC_TPLG_DAPM_DAI_LINK     15
+#define SND_SOC_TPLG_DAPM_LAST         SND_SOC_TPLG_DAPM_DAI_LINK
+
+/* Header magic number and string sizes */
+#define SND_SOC_TPLG_MAGIC             0x41536F43 /* ASoC */
+
+/* string sizes */
+#define SND_SOC_TPLG_NUM_TEXTS         16
+
+/* ABI version */
+#define SND_SOC_TPLG_ABI_VERSION       0x3
+
+/* Max size of TLV data */
+#define SND_SOC_TPLG_TLV_SIZE          32
+
+/*
+ * File and Block header data types.
+ * Add new generic and vendor types to end of list.
+ * Generic types are handled by the core whilst vendors types are passed
+ * to the component drivers for handling.
+ */
+#define SND_SOC_TPLG_TYPE_MIXER                1
+#define SND_SOC_TPLG_TYPE_BYTES                2
+#define SND_SOC_TPLG_TYPE_ENUM         3
+#define SND_SOC_TPLG_TYPE_DAPM_GRAPH   4
+#define SND_SOC_TPLG_TYPE_DAPM_WIDGET  5
+#define SND_SOC_TPLG_TYPE_DAI_LINK     6
+#define SND_SOC_TPLG_TYPE_PCM          7
+#define SND_SOC_TPLG_TYPE_MANIFEST     8
+#define SND_SOC_TPLG_TYPE_CODEC_LINK   9
+#define SND_SOC_TPLG_TYPE_PDATA                10
+#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_PDATA
+
+/* vendor block IDs - please add new vendor types to end */
+#define SND_SOC_TPLG_TYPE_VENDOR_FW    1000
+#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG        1001
+#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002
+#define SND_SOC_TPLG_TYPEVENDOR_CODEC  1003
+
+#define SND_SOC_TPLG_STREAM_PLAYBACK   0
+#define SND_SOC_TPLG_STREAM_CAPTURE    1
+
+/*
+ * Block Header.
+ * This header precedes all object and object arrays below.
+ */
+struct snd_soc_tplg_hdr {
+       __le32 magic;           /* magic number */
+       __le32 abi;             /* ABI version */
+       __le32 version;         /* optional vendor specific version details */
+       __le32 type;            /* SND_SOC_TPLG_TYPE_ */
+       __le32 size;            /* size of this structure */
+       __le32 vendor_type;     /* optional vendor specific type info */
+       __le32 payload_size;    /* data bytes, excluding this header */
+       __le32 index;           /* identifier for block */
+       __le32 count;           /* number of elements in block */
+} __attribute__((packed));
+
+/*
+ * Private data.
+ * All topology objects may have private data that can be used by the driver or
+ * firmware. Core will ignore this data.
+ */
+struct snd_soc_tplg_private {
+       __le32 size;    /* in bytes of private data */
+       char data[0];
+} __attribute__((packed));
+
+/*
+ * Kcontrol TLV data.
+ */
+struct snd_soc_tplg_ctl_tlv {
+       __le32 size;    /* in bytes aligned to 4 */
+       __le32 numid;   /* control element numeric identification */
+       __le32 count;   /* number of elem in data array */
+       __le32 data[SND_SOC_TPLG_TLV_SIZE];
+} __attribute__((packed));
+
+/*
+ * Kcontrol channel data
+ */
+struct snd_soc_tplg_channel {
+       __le32 size;    /* in bytes of this structure */
+       __le32 reg;
+       __le32 shift;
+       __le32 id;      /* ID maps to Left, Right, LFE etc */
+} __attribute__((packed));
+
+/*
+ * Kcontrol Operations IDs
+ */
+struct snd_soc_tplg_kcontrol_ops_id {
+       __le32 get;
+       __le32 put;
+       __le32 info;
+} __attribute__((packed));
+
+/*
+ * kcontrol header
+ */
+struct snd_soc_tplg_ctl_hdr {
+       __le32 size;    /* in bytes of this structure */
+       __le32 type;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 access;
+       struct snd_soc_tplg_kcontrol_ops_id ops;
+       __le32 tlv_size;        /* non zero means control has TLV data */
+} __attribute__((packed));
+
+/*
+ * Stream Capabilities
+ */
+struct snd_soc_tplg_stream_caps {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le64 formats[SND_SOC_TPLG_MAX_FORMATS];       /* supported formats 
SNDRV_PCM_FMTBIT_* */
+       __le32 rates;           /* supported rates SNDRV_PCM_RATE_* */
+       __le32 rate_min;        /* min rate */
+       __le32 rate_max;        /* max rate */
+       __le32 channels_min;    /* min channels */
+       __le32 channels_max;    /* max channels */
+       __le32 periods_min;     /* min number of periods */
+       __le32 periods_max;     /* max number of periods */
+       __le32 period_size_min; /* min period size bytes */
+       __le32 period_size_max; /* max period size bytes */
+       __le32 buffer_size_min; /* min buffer size bytes */
+       __le32 buffer_size_max; /* max buffer size bytes */
+} __attribute__((packed));
+
+/*
+ * FE or BE Stream configuration supported by SW/FW
+ */
+struct snd_soc_tplg_stream {
+       __le32 size;            /* in bytes of this structure */
+       __le64 format;          /* SNDRV_PCM_FMTBIT_* */
+       __le32 rate;            /* SNDRV_PCM_RATE_* */
+       __le32 period_bytes;    /* size of period in bytes */
+       __le32 buffer_bytes;    /* size of buffer in bytes */
+       __le32 channels;        /* channels */
+       __le32 tdm_slot;        /* optional BE bitmask of supported TDM slots */
+       __le32 dai_fmt;         /* SND_SOC_DAIFMT_  */
+} __attribute__((packed));
+
+/*
+ * Duplex stream configuration supported by SW/FW.
+ */
+struct snd_soc_tplg_stream_config {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       struct snd_soc_tplg_stream playback;
+       struct snd_soc_tplg_stream capture;
+} __attribute__((packed));
+
+/*
+ * Manifest. List totals for each payload type. Not used in parsing, but will
+ * be passed to the component driver before any other objects in order for any
+ * global component resource allocations.
+ *
+ * File block representation for manifest :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_manifest      |  1 |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_manifest {
+       __le32 size;            /* in bytes of this structure */
+       __le32 control_elems;   /* number of control elements */
+       __le32 widget_elems;    /* number of widget elements */
+       __le32 graph_elems;     /* number of graph elements */
+       __le32 dai_elems;       /* number of DAI elements */
+       __le32 dai_link_elems;  /* number of DAI link elements */
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Mixer kcontrol.
+ *
+ * File block representation for mixer kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_mixer_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_mixer_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 min;
+       __le32 max;
+       __le32 platform_max;
+       __le32 invert;
+       __le32 num_channels;
+       struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+       struct snd_soc_tplg_ctl_tlv tlv;
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Enumerated kcontrol
+ *
+ * File block representation for enum kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_enum_control  |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_enum_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 num_channels;
+       struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
+       __le32 items;
+       __le32 mask;
+       __le32 count;
+       char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 
4];
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * Bytes kcontrol
+ *
+ * File block representation for bytes kcontrol :-
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_hdr           |  1 |
+ * +-----------------------------------+----+
+ * | struct snd_soc_tplg_bytes_control |  N |
+ * +-----------------------------------+----+
+ */
+struct snd_soc_tplg_bytes_control {
+       struct snd_soc_tplg_ctl_hdr hdr;
+       __le32 size;    /* in bytes of this structure */
+       __le32 max;
+       __le32 mask;
+       __le32 base;
+       __le32 num_regs;
+       struct snd_soc_tplg_private priv;
+} __attribute__((packed));
+
+/*
+ * DAPM Graph Element
+ *
+ * File block representation for DAPM graph elements :-
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_hdr             |  1 |
+ * +-------------------------------------+----+
+ * | struct snd_soc_tplg_dapm_graph_elem |  N |
+ * +-------------------------------------+----+
+ */
+struct snd_soc_tplg_dapm_graph_elem {
+       char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+} __attribute__((packed));
+
+/*
+ * DAPM Widget.
+ *
+ * File block representation for DAPM widget :-
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_hdr             |  1  |
+ * +-------------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_widget     |  N  |
+ * +-------------------------------------+-----+
+ * |   struct snd_soc_tplg_enum_control  | 0|1 |
+ * |   struct snd_soc_tplg_mixer_control | 0|N |
+ * +-------------------------------------+-----+
+ *
+ * Optional enum or mixer control can be appended to the end of each widget
+ * in the block.
+ */
+struct snd_soc_tplg_dapm_widget {
+       __le32 size;            /* in bytes of this structure */
+       __le32 id;              /* SND_SOC_DAPM_CTL */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       __le32 reg;             /* negative reg = no direct dapm */
+       __le32 shift;           /* bits to shift */
+       __le32 mask;            /* non-shifted mask */
+       __le32 subseq;          /* sort within widget type */
+       __u32 invert;           /* invert the power bit */
+       __u32 ignore_suspend;   /* kept enabled over suspend */
+       __u16 event_flags;
+       __u16 event_type;
+       __u16 num_kcontrols;
+       struct snd_soc_tplg_private priv;
+       /*
+        * kcontrols that relate to this widget
+        * follow here after widget private data
+        */
+} __attribute__((packed));
+
+struct snd_soc_tplg_pcm_cfg_caps {
+       struct snd_soc_tplg_stream_caps caps;
+       struct snd_soc_tplg_stream_config 
configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
+       __le32 num_configs;     /* number of configs */
+} __attribute__((packed));
+
+/*
+ * Describes SW/FW specific features of PCM or DAI link.
+ *
+ * File block representation for PCM/DAI-Link :-
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_hdr           |  1  |
+ * +-----------------------------------+-----+
+ * | struct snd_soc_tplg_dapm_pcm_dai  |  N  |
+ * +-----------------------------------+-----+
+ */
+struct snd_soc_tplg_pcm_dai {
+       __le32 size;            /* in bytes of this structure */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       __le32 id;                      /* unique ID - used to match */
+       __le32 playback;                /* supports playback mode */
+       __le32 capture;                 /* supports capture mode */
+       __le32 compress;                /* 1 = compressed; 0 = PCM */
+       struct snd_soc_tplg_pcm_cfg_caps capconf[2];    /* capabilities and 
configs */
+} __attribute__((packed));
+
+#endif
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
new file mode 100644
index 000000000000..33d747df1410
--- /dev/null
+++ b/include/sound/tlv.h
@@ -0,0 +1,23 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 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.
+ */
+
+#ifndef __UAPI_SOUND_TLV_H
+#define __UAPI_SOUND_TLV_H
+
+#define SNDRV_CTL_TLVT_CONTAINER 0     /* one level down - group of TLVs */
+#define SNDRV_CTL_TLVT_DB_SCALE        1       /* dB scale */
+#define SNDRV_CTL_TLVT_DB_LINEAR 2     /* linear volume */
+#define SNDRV_CTL_TLVT_DB_RANGE 3      /* dB range container */
+#define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
+#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with 
mute */
+
+#endif
-- 
2.5.0

++++++ 0036-topology-Add-topology-core-parser.patch ++++++
++++ 1326 lines (skipped)

++++++ 0037-topology-Add-text-section-parser.patch ++++++
>From 408396a8ca092846c840baa79c04b5f7dbe5da69 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:15 +0100
Subject: [PATCH 37/49] topology: Add text section parser.

Parse text lists (like enum values) and store for later attachment
to other objects.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/text.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 src/topology/text.c

diff --git a/src/topology/text.c b/src/topology/text.c
new file mode 100644
index 000000000000..ebb6e3840d62
--- /dev/null
+++ b/src/topology/text.c
@@ -0,0 +1,88 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+#define TEXT_SIZE_MAX \
+       (SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+
+static int parse_text_values(snd_config_t *cfg, struct tplg_elem *elem)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *value = NULL;
+       int j = 0;
+
+       tplg_dbg(" Text Values: %s\n", elem->id);
+
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+
+               if (j == SND_SOC_TPLG_NUM_TEXTS) {
+                       tplg_dbg("error: text string number exceeds %d\n", j);
+                       return -ENOMEM;
+               }
+
+               /* get value */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               elem_copy_text(&elem->texts[j][0], value,
+                       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+               tplg_dbg("\t%s\n", &elem->texts[j][0]);
+
+               j++;
+       }
+
+       return 0;
+}
+
+/* Parse Text data */
+int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg,
+       void *private ATTRIBUTE_UNUSED)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id;
+       int err = 0;
+       struct tplg_elem *elem;
+
+       elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_TEXT);
+       if (!elem)
+               return -ENOMEM;
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, "values") == 0) {
+                       err = parse_text_values(n, elem);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse text values");
+                               return err;
+                       }
+                       continue;
+               }
+       }
+
+       return err;
+}
-- 
2.5.0

++++++ 0038-topology-Add-PCM-parser.patch ++++++
++++ 664 lines (skipped)

++++++ 0039-topology-Add-operations-parser.patch ++++++
>From 353f1eddb608a837157342155fc061f85bf0a5f8 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:17 +0100
Subject: [PATCH 39/49] topology: Add operations parser

Parse operations so we can bind them to kcontrols in the kernel.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/ops.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 src/topology/ops.c

diff --git a/src/topology/ops.c b/src/topology/ops.c
new file mode 100644
index 000000000000..243d8c5e2bbc
--- /dev/null
+++ b/src/topology/ops.c
@@ -0,0 +1,84 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+/* mapping of kcontrol text names to types */
+static const struct map_elem control_map[] = {
+       {"volsw", SND_SOC_TPLG_CTL_VOLSW},
+       {"volsw_sx", SND_SOC_TPLG_CTL_VOLSW_SX},
+       {"volsw_xr_sx", SND_SOC_TPLG_CTL_VOLSW_XR_SX},
+       {"enum", SND_SOC_TPLG_CTL_ENUM},
+       {"bytes", SND_SOC_TPLG_CTL_BYTES},
+       {"enum_value", SND_SOC_TPLG_CTL_ENUM_VALUE},
+       {"range", SND_SOC_TPLG_CTL_RANGE},
+       {"strobe", SND_SOC_TPLG_CTL_STROBE},
+};
+
+static int lookup_ops(const char *c)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(control_map); i++) {
+               if (strcmp(control_map[i].name, c) == 0)
+                       return control_map[i].id;
+       }
+
+       /* cant find string name in our table so we use its ID number */
+       return atoi(c);
+}
+
+/* Parse Control operations. Ops can come from standard names above or
+ * bespoke driver controls with numbers >= 256
+ */
+int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
+       snd_config_t *cfg, void *private)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       struct snd_soc_tplg_ctl_hdr *hdr = private;
+       const char *id, *value;
+
+       tplg_dbg("\tOps\n");
+       hdr->size = sizeof(*hdr);
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+
+               /* get id */
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* get value - try strings then ints */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               if (strcmp(id, "info") == 0)
+                       hdr->ops.info = lookup_ops(value);
+               else if (strcmp(id, "put") == 0)
+                       hdr->ops.put = lookup_ops(value);
+               else if (strcmp(id, "get") == 0)
+                       hdr->ops.get = lookup_ops(value);
+
+               tplg_dbg("\t\t%s = %s\n", id, value);
+       }
+
+       return 0;
+}
-- 
2.5.0

++++++ 0040-topology-Add-private-data-parser.patch ++++++
>From 5b379da2a0a1084349e918a52f471c03e37af703 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:18 +0100
Subject: [PATCH 40/49] topology: Add private data parser

Parse private data and store for attachment to other objects. Data can come
file or be locally defined as bytes, shorts or words.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/data.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 396 insertions(+)
 create mode 100644 src/topology/data.c

diff --git a/src/topology/data.c b/src/topology/data.c
new file mode 100644
index 000000000000..ae664721935d
--- /dev/null
+++ b/src/topology/data.c
@@ -0,0 +1,396 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+/* Get Private data from a file. */
+static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
+{
+       struct snd_soc_tplg_private *priv = NULL;
+       const char *value = NULL;
+       char filename[MAX_FILE];
+       char *env = getenv(ALSA_CONFIG_TPLG_VAR);
+       FILE *fp;
+       size_t size, bytes_read;
+       int ret = 0;
+
+       tplg_dbg("data DataFile: %s\n", elem->id);
+
+       if (snd_config_get_string(cfg, &value) < 0)
+               return -EINVAL;
+
+       /* prepend alsa config directory to path */
+       snprintf(filename, sizeof(filename), "%s/%s",
+               env ? env : ALSA_TPLG_DIR, value);
+
+       fp = fopen(filename, "r");
+       if (fp == NULL) {
+               SNDERR("error: invalid data file path '%s'\n",
+                       filename);
+               ret = -errno;
+               goto err;
+       }
+
+       fseek(fp, 0L, SEEK_END);
+       size = ftell(fp);
+       fseek(fp, 0L, SEEK_SET);
+       if (size <= 0) {
+               SNDERR("error: invalid data file size %zu\n", size);
+               ret = -EINVAL;
+               goto err;
+       }
+       if (size > TPLG_MAX_PRIV_SIZE) {
+               SNDERR("error: data file too big %zu\n", size);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       priv = calloc(1, sizeof(*priv) + size);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       bytes_read = fread(&priv->data, 1, size, fp);
+       if (bytes_read != size) {
+               ret = -errno;
+               goto err;
+       }
+
+       elem->data = priv;
+       priv->size = size;
+       elem->size = sizeof(*priv) + size;
+       return 0;
+
+err:
+       if (priv)
+               free(priv);
+       return ret;
+}
+
+static void dump_priv_data(struct tplg_elem *elem)
+{
+       struct snd_soc_tplg_private *priv = elem->data;
+       unsigned char *p = (unsigned char *)priv->data;
+       unsigned int i, j = 0;
+
+       tplg_dbg(" elem size = %d, priv data size = %d\n",
+               elem->size, priv->size);
+
+       for (i = 0; i < priv->size; i++) {
+               if (j++ % 8 == 0)
+                       tplg_dbg("\n");
+
+               tplg_dbg(" 0x%x", *p++);
+       }
+
+       tplg_dbg("\n\n");
+}
+
+/* get number of hex value elements in CSV list */
+static int get_hex_num(const char *str)
+{
+       int commas = 0, values = 0, len = strlen(str);
+       const char *end = str + len;
+
+       /* we expect "0x0, 0x0, 0x0" */
+       while (str < end) {
+
+               /* skip white space */
+               if (isspace(*str)) {
+                       str++;
+                       continue;
+               }
+
+               /* find delimeters */
+               if (*str == ',') {
+                       commas++;
+                       str++;
+                       continue;
+               }
+
+               /* find 0x[0-9] values */
+               if (*str == '0' && str + 2 <= end) {
+                       if (str[1] == 'x' && str[2] >= '0' && str[2] <= 'f') {
+                               values++;
+                               str += 3;
+                       } else {
+                               str++;
+                       }
+               }
+
+               str++;
+       }
+
+       /* there should always be one less comma than value */
+       if (values -1 != commas)
+               return -EINVAL;
+
+       return values;
+}
+
+static int write_hex(char *buf, char *str, int width)
+{
+       long val;
+       void *p = &val;
+
+        errno = 0;
+       val = strtol(str, NULL, 16);
+
+       if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+               || (errno != 0 && val == 0)) {
+               return -EINVAL;
+        }
+
+       switch (width) {
+       case 1:
+               *(unsigned char *)buf = *(unsigned char *)p;
+               break;
+       case 2:
+               *(unsigned short *)buf = *(unsigned short *)p;
+               break;
+       case 4:
+               *(unsigned int *)buf = *(unsigned int *)p;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int copy_data_hex(char *data, int off, const char *str, int width)
+{
+       char *tmp, *s = NULL, *p = data;
+       int ret;
+
+       tmp = strdup(str);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       p += off;
+       s = strtok(tmp, ",");
+
+       while (s != NULL) {
+               ret = write_hex(p, s, width);
+               if (ret < 0) {
+                       free(tmp);
+                       return ret;
+               }
+
+               s = strtok(NULL, ",");
+               p += width;
+       }
+
+       free(tmp);
+       return 0;
+}
+
+static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
+       int width)
+{
+       struct snd_soc_tplg_private *priv;
+       const char *value = NULL;
+       int size, esize, off, num;
+       int ret;
+
+       tplg_dbg(" data: %s\n", elem->id);
+
+       if (snd_config_get_string(cfg, &value) < 0)
+               return -EINVAL;
+
+       num = get_hex_num(value);
+       if (num <= 0) {
+               SNDERR("error: malformed hex variable list %s\n", value);
+               return -EINVAL;
+       }
+
+       size = num * width;
+       priv = elem->data;
+
+       if (esize > TPLG_MAX_PRIV_SIZE) {
+               SNDERR("error: data too big %d\n", esize);
+               return -EINVAL;
+       }
+
+       if (priv != NULL) {
+               off = priv->size;
+               esize = elem->size + size;
+               priv = realloc(priv, esize);
+       } else {
+               off = 0;
+               esize = sizeof(*priv) + size;
+               priv = calloc(1, esize);
+       }
+
+       if (!priv)
+               return -ENOMEM;
+
+       elem->data = priv;
+       priv->size += size;
+       elem->size = esize;
+
+       ret = copy_data_hex(priv->data, off, value, width);
+
+       dump_priv_data(elem);
+       return ret;
+}
+
+
+/* Parse Private data.
+ *
+ * Object private data can either be from file or defined as bytes, shorts,
+ * words.
+ */
+int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
+       void *private ATTRIBUTE_UNUSED)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id, *val = NULL;
+       int err = 0;
+       struct tplg_elem *elem;
+
+       elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DATA);
+       if (!elem)
+               return -ENOMEM;
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0) {
+                       continue;
+               }
+
+               if (strcmp(id, "file") == 0) {
+                       err = tplg_parse_data_file(n, elem);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse data file\n");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "bytes") == 0) {
+                       err = tplg_parse_data_hex(n, elem, 1);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse data bytes\n");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "shorts") == 0) {
+                       err = tplg_parse_data_hex(n, elem, 2);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse data shorts\n");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "words") == 0) {
+                       err = tplg_parse_data_hex(n, elem, 4);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse data words\n");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "index") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       elem->index = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, elem->index);
+                       continue;
+               }
+
+               if (strcmp(id, "type") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       elem->vendor_type = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, elem->index);
+                       continue;
+               }
+       }
+
+       return err;
+}
+
+/* copy private data into the bytes extended control */
+int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
+{
+       struct snd_soc_tplg_private *priv;
+       int priv_data_size;
+
+       if (!ref)
+               return -EINVAL;
+
+       tplg_dbg("Data '%s' used by '%s'\n", ref->id, elem->id);
+       priv_data_size = ref->data->size;
+
+       switch (elem->type) {
+       case OBJECT_TYPE_MIXER:
+               elem->mixer_ctrl = realloc(elem->mixer_ctrl,
+                       elem->size + priv_data_size);
+               if (!elem->mixer_ctrl)
+                       return -ENOMEM;
+               priv = &elem->mixer_ctrl->priv;
+               break;
+
+       case OBJECT_TYPE_ENUM:
+               elem->enum_ctrl = realloc(elem->enum_ctrl,
+                       elem->size + priv_data_size);
+               if (!elem->enum_ctrl)
+                       return -ENOMEM;
+               priv = &elem->enum_ctrl->priv;
+               break;
+
+       case OBJECT_TYPE_BYTES:
+               elem->bytes_ext = realloc(elem->bytes_ext,
+                       elem->size + priv_data_size);
+               if (!elem->bytes_ext)
+                       return -ENOMEM;
+               priv = &elem->bytes_ext->priv;
+               break;
+
+
+       case OBJECT_TYPE_DAPM_WIDGET:
+               elem->widget = realloc(elem->widget,
+                       elem->size + priv_data_size);
+               if (!elem->widget)
+                       return -ENOMEM;
+               priv = &elem->widget->priv;
+               break;
+
+       default:
+               SNDERR("elem '%s': type %d private data not supported \n",
+                       elem->id, elem->type);
+               return -EINVAL;
+       }
+
+       elem->size += priv_data_size;
+       priv->size = priv_data_size;
+       ref->compound_elem = 1;
+       memcpy(priv->data, ref->data->data, priv_data_size);
+       return 0;
+}
-- 
2.5.0

++++++ 0041-topology-Add-DAPM-object-parser.patch ++++++
>From 01a0e1a1c2196967d2522092ca993098a7c66613 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:19 +0100
Subject: [PATCH 41/49] topology: Add DAPM object parser

Parse DAPM objects including widgets and graph elements.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/dapm.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 562 insertions(+)
 create mode 100644 src/topology/dapm.c

diff --git a/src/topology/dapm.c b/src/topology/dapm.c
new file mode 100644
index 000000000000..1da82adea470
--- /dev/null
+++ b/src/topology/dapm.c
@@ -0,0 +1,562 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+/* mapping of widget text names to types */
+static const struct map_elem widget_map[] = {
+       {"input", SND_SOC_TPLG_DAPM_INPUT},
+       {"output", SND_SOC_TPLG_DAPM_OUTPUT},
+       {"mux", SND_SOC_TPLG_DAPM_MUX},
+       {"mixer", SND_SOC_TPLG_DAPM_MIXER},
+       {"pga", SND_SOC_TPLG_DAPM_PGA},
+       {"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV},
+       {"adc", SND_SOC_TPLG_DAPM_ADC},
+       {"dac", SND_SOC_TPLG_DAPM_DAC},
+       {"switch", SND_SOC_TPLG_DAPM_SWITCH},
+       {"pre", SND_SOC_TPLG_DAPM_PRE},
+       {"post", SND_SOC_TPLG_DAPM_POST},
+       {"aif_in", SND_SOC_TPLG_DAPM_AIF_IN},
+       {"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT},
+       {"dai_in", SND_SOC_TPLG_DAPM_DAI_IN},
+       {"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT},
+       {"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;
+
+       for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
+               if (strcmp(widget_map[i].name, w) == 0)
+                       return widget_map[i].id;
+       }
+
+       return -EINVAL;
+}
+
+static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *value = NULL;
+
+       tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id);
+
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+
+               /* get value */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               tplg_ref_add(elem, OBJECT_TYPE_MIXER, value);
+               tplg_dbg("\t\t %s\n", value);
+       }
+
+       return 0;
+}
+
+static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *value = NULL;
+
+       tplg_dbg(" DAPM Enum Controls: %s\n", elem->id);
+
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+
+               /* get value */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               tplg_ref_add(elem, OBJECT_TYPE_ENUM, value);
+               tplg_dbg("\t\t %s\n", value);
+       }
+
+       return 0;
+}
+
+/* move referenced controls to the widget */
+static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref)
+{
+       struct snd_soc_tplg_dapm_widget *widget = elem->widget;
+       struct snd_soc_tplg_mixer_control *mixer_ctrl = ref->mixer_ctrl;
+       struct snd_soc_tplg_enum_control *enum_ctrl = ref->enum_ctrl;
+
+       tplg_dbg("Control '%s' used by '%s'\n", ref->id, elem->id);
+       tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d\n",
+               elem->size, ref->size, elem->size + ref->size,
+               widget->priv.size);
+
+       widget = realloc(widget, elem->size + ref->size);
+       if (!widget)
+               return -ENOMEM;
+
+       elem->widget = widget;
+
+       /* copy new widget at the end */
+       if (ref->type == OBJECT_TYPE_MIXER)
+               memcpy((void*)widget + elem->size, mixer_ctrl, ref->size);
+       else if (ref->type == OBJECT_TYPE_ENUM)
+               memcpy((void*)widget + elem->size, enum_ctrl, ref->size);
+
+       elem->size += ref->size;
+       widget->num_kcontrols++;
+       ref->compound_elem = 1;
+       return 0;
+}
+
+/* check referenced controls for a widget */
+static int tplg_build_widget(snd_tplg_t *tplg,
+       struct tplg_elem *elem)
+{
+       struct tplg_ref *ref;
+       struct list_head *base, *pos;
+       int err = 0;
+
+       base = &elem->ref_list;
+
+       /* for each ref in this control elem */
+       list_for_each(pos, base) {
+
+               ref = list_entry(pos, struct tplg_ref, list);
+               if (ref->id == NULL || ref->elem)
+                       continue;
+
+               switch (ref->type) {
+               case OBJECT_TYPE_MIXER:
+                       ref->elem = tplg_elem_lookup(&tplg->mixer_list,
+                                               ref->id, OBJECT_TYPE_MIXER);
+                       if (ref->elem)
+                               err = copy_dapm_control(elem, ref->elem);
+                       break;
+
+               case OBJECT_TYPE_ENUM:
+                       ref->elem = tplg_elem_lookup(&tplg->enum_list,
+                                               ref->id, OBJECT_TYPE_ENUM);
+                       if (ref->elem)
+                               err = copy_dapm_control(elem, ref->elem);
+                       break;
+
+               case OBJECT_TYPE_DATA:
+                       ref->elem = tplg_elem_lookup(&tplg->pdata_list,
+                                               ref->id, OBJECT_TYPE_DATA);
+                       if (ref->elem)
+                               err = tplg_copy_data(elem, ref->elem);
+                       break;
+               default:
+                       break;
+               }
+
+               if (!ref->elem) {
+                       SNDERR("error: cannot find control '%s'"
+                               " referenced by widget '%s'\n",
+                               ref->id, elem->id);
+                       return -EINVAL;
+               }
+
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int tplg_build_widgets(snd_tplg_t *tplg)
+{
+
+       struct list_head *base, *pos;
+       struct tplg_elem *elem;
+       int err;
+
+       base = &tplg->widget_list;
+       list_for_each(pos, base) {
+
+               elem = list_entry(pos, struct tplg_elem, list);
+               if (!elem->widget || elem->type != OBJECT_TYPE_DAPM_WIDGET) {
+                       SNDERR("error: invalid widget '%s'\n",
+                               elem->id);
+                       return -EINVAL;
+               }
+
+               err = tplg_build_widget(tplg, elem);
+               if (err < 0)
+                       return err;
+
+               /* add widget to manifest */
+               tplg->manifest.widget_elems++;
+       }
+
+       return 0;
+}
+
+int tplg_build_routes(snd_tplg_t *tplg)
+{
+       struct list_head *base, *pos;
+       struct tplg_elem *elem;
+       struct snd_soc_tplg_dapm_graph_elem *route;
+
+       base = &tplg->route_list;
+
+       list_for_each(pos, base) {
+               elem = list_entry(pos, struct tplg_elem, list);
+
+               if (!elem->route || elem->type != OBJECT_TYPE_DAPM_GRAPH) {
+                       SNDERR("error: invalid route '%s'\n",
+                               elem->id);
+                       return -EINVAL;
+               }
+
+               route = elem->route;
+               tplg_dbg("\nCheck route: sink '%s', control '%s', source 
'%s'\n",
+                       route->sink, route->control, route->source);
+
+               /* validate sink */
+               if (strlen(route->sink) <= 0) {
+                       SNDERR("error: no sink\n");
+                       return -EINVAL;
+
+               }
+               if (!tplg_elem_lookup(&tplg->widget_list, route->sink,
+                       OBJECT_TYPE_DAPM_WIDGET)) {
+                       SNDERR("warning: undefined sink widget/stream '%s'\n",
+                               route->sink);
+               }
+
+               /* validate control name */
+               if (strlen(route->control)) {
+                       if (!tplg_elem_lookup(&tplg->mixer_list,
+                               route->control, OBJECT_TYPE_MIXER) &&
+                       !tplg_elem_lookup(&tplg->enum_list,
+                               route->control, OBJECT_TYPE_ENUM)) {
+                               SNDERR("warning: Undefined mixer/enum control 
'%s'\n",
+                                       route->control);
+                       }
+               }
+
+               /* validate source */
+               if (strlen(route->source) <= 0) {
+                       SNDERR("error: no source\n");
+                       return -EINVAL;
+
+               }
+               if (!tplg_elem_lookup(&tplg->widget_list, route->source,
+                       OBJECT_TYPE_DAPM_WIDGET)) {
+                       SNDERR("warning: Undefined source widget/stream '%s'\n",
+                               route->source);
+               }
+
+               /* add graph to manifest */
+               tplg->manifest.graph_elems++;
+       }
+
+       return 0;
+}
+
+#define LINE_SIZE      1024
+
+/* line is defined as '"source, control, sink"' */
+static int tplg_parse_line(const char *text,
+       struct snd_soc_tplg_dapm_graph_elem *line)
+{
+       char buf[LINE_SIZE];
+       unsigned int len, i;
+       const char *source = NULL, *sink = NULL, *control = NULL;
+
+       elem_copy_text(buf, text, LINE_SIZE);
+
+       len = strlen(buf);
+       if (len <= 2) {
+               SNDERR("error: invalid route \"%s\"\n", buf);
+               return -EINVAL;
+       }
+
+       /* find first , */
+       for (i = 1; i < len; i++) {
+               if (buf[i] == ',')
+                       goto second;
+       }
+       SNDERR("error: invalid route \"%s\"\n", buf);
+       return -EINVAL;
+
+second:
+       /* find second , */
+       sink = buf;
+       control = &buf[i + 2];
+       buf[i] = 0;
+
+       for (; i < len; i++) {
+               if (buf[i] == ',')
+                       goto done;
+       }
+
+       SNDERR("error: invalid route \"%s\"\n", buf);
+       return -EINVAL;
+
+done:
+       buf[i] = 0;
+       source = &buf[i + 2];
+
+       strcpy(line->source, source);
+       strcpy(line->control, control);
+       strcpy(line->sink, sink);
+       return 0;
+}
+
+
+static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       struct tplg_elem *elem;
+       struct snd_soc_tplg_dapm_graph_elem *line = NULL;
+       int err;
+
+       snd_config_for_each(i, next, cfg) {
+               const char *val;
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_string(n, &val) < 0)
+                       continue;
+
+               elem = tplg_elem_new();
+               if (!elem)
+                       return -ENOMEM;
+
+               list_add_tail(&elem->list, &tplg->route_list);
+               strcpy(elem->id, "line");
+               elem->type = OBJECT_TYPE_DAPM_GRAPH;
+               elem->size = sizeof(*line);
+
+               line = calloc(1, sizeof(*line));
+               if (!line)
+                       return -ENOMEM;
+
+               elem->route = line;
+
+               err = tplg_parse_line(val, line);
+               if (err < 0)
+                       return err;
+
+               tplg_dbg("route: sink '%s', control '%s', source '%s'\n",
+                               line->sink, line->control, line->source);
+       }
+
+       return 0;
+}
+
+int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
+       void *private ATTRIBUTE_UNUSED)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+       const char *graph_id;
+
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               SNDERR("error: compound is expected for dapm graph 
definition\n");
+               return -EINVAL;
+       }
+
+       snd_config_get_id(cfg, &graph_id);
+
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0) {
+                       continue;
+               }
+
+               if (strcmp(id, "lines") == 0) {
+                       err = tplg_parse_routes(tplg, n);
+                       if (err < 0) {
+                               SNDERR("error: failed to parse dapm graph %s\n",
+                                       graph_id);
+                               return err;
+                       }
+                       continue;
+               }
+       }
+
+       return 0;
+}
+
+/* DAPM Widget */
+int tplg_parse_dapm_widget(snd_tplg_t *tplg,
+       snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
+{
+       struct snd_soc_tplg_dapm_widget *widget;
+       struct tplg_elem *elem;
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id, *val = NULL;
+       int widget_type, err;
+
+       elem = tplg_elem_new_common(tplg, cfg, OBJECT_TYPE_DAPM_WIDGET);
+       if (!elem)
+               return -ENOMEM;
+
+       tplg_dbg(" Widget: %s\n", elem->id);
+
+       widget = elem->widget;
+       elem_copy_text(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+       widget->size = elem->size;
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* skip comments */
+               if (strcmp(id, "comment") == 0)
+                       continue;
+               if (id[0] == '#')
+                       continue;
+
+               if (strcmp(id, "index") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       elem->index = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, elem->index);
+                       continue;
+               }
+
+               if (strcmp(id, "type") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget_type = lookup_widget(val);
+                       if (widget_type < 0){
+                               SNDERR("Widget '%s': Unsupported widget type 
%s\n",
+                                       elem->id, val);
+                               return -EINVAL;
+                       }
+
+                       widget->id = widget_type;
+                       tplg_dbg("\t%s: %s\n", id, val);
+                       continue;
+               }
+
+               if (strcmp(id, "no_pm") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       if (strcmp(val, "true") == 0)
+                               widget->reg = -1;
+
+                       tplg_dbg("\t%s: %s\n", id, val);
+                       continue;
+               }
+
+               if (strcmp(id, "shift") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->shift = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->shift);
+                       continue;
+               }
+
+               if (strcmp(id, "reg") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->reg = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->reg);
+                       continue;
+               }
+
+               if (strcmp(id, "invert") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->invert = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->invert);
+                       continue;
+               }
+
+               if (strcmp(id, "subseq") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->subseq= atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->subseq);
+                       continue;
+               }
+
+               if (strcmp(id, "event_type") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->event_type = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->event_type);
+                       continue;
+               }
+
+               if (strcmp(id, "event_flags") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       widget->event_flags = atoi(val);
+                       tplg_dbg("\t%s: %d\n", id, widget->event_flags);
+                       continue;
+               }
+
+               if (strcmp(id, "enum") == 0) {
+                       err = tplg_parse_dapm_enums(n, elem);
+                       if (err < 0)
+                               return err;
+
+                       continue;
+               }
+
+               if (strcmp(id, "mixer") == 0) {
+                       err = tplg_parse_dapm_mixers(n, elem);
+                       if (err < 0)
+                               return err;
+
+                       continue;
+               }
+
+               if (strcmp(id, "data") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+
+                       tplg_ref_add(elem, OBJECT_TYPE_DATA, val);
+                       tplg_dbg("\t%s: %s\n", id, val);
+                       continue;
+               }
+       }
+
+       return 0;
+}
-- 
2.5.0

++++++ 0042-topology-Add-CTL-parser.patch ++++++
++++ 636 lines (skipped)

++++++ 0043-topology-Add-Channel-map-parser.patch ++++++
>From 9764a4b891737e6b4363c09b5e5ce8384acecc11 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:21 +0100
Subject: [PATCH 43/49] topology: Add Channel map parser.

Add support for parsing channel map to control registers.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/channel.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
 create mode 100644 src/topology/channel.c

diff --git a/src/topology/channel.c b/src/topology/channel.c
new file mode 100644
index 000000000000..9bc5d5a77c57
--- /dev/null
+++ b/src/topology/channel.c
@@ -0,0 +1,122 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+/* mapping of channel text names to types */
+static const struct map_elem channel_map[] = {
+       {"mono", SNDRV_CHMAP_MONO},     /* mono stream */
+       {"fl", SNDRV_CHMAP_FL},         /* front left */
+       {"fr", SNDRV_CHMAP_FR},         /* front right */
+       {"rl", SNDRV_CHMAP_RL},         /* rear left */
+       {"rr", SNDRV_CHMAP_RR},         /* rear right */
+       {"fc", SNDRV_CHMAP_FC},         /* front center */
+       {"lfe", SNDRV_CHMAP_LFE},       /* LFE */
+       {"sl", SNDRV_CHMAP_SL},         /* side left */
+       {"sr", SNDRV_CHMAP_SR},         /* side right */
+       {"rc", SNDRV_CHMAP_RC},         /* rear center */
+       {"flc", SNDRV_CHMAP_FLC},       /* front left center */
+       {"frc", SNDRV_CHMAP_FRC},       /* front right center */
+       {"rlc", SNDRV_CHMAP_RLC},       /* rear left center */
+       {"rrc", SNDRV_CHMAP_RRC},       /* rear right center */
+       {"flw", SNDRV_CHMAP_FLW},       /* front left wide */
+       {"frw", SNDRV_CHMAP_FRW},       /* front right wide */
+       {"flh", SNDRV_CHMAP_FLH},       /* front left high */
+       {"fch", SNDRV_CHMAP_FCH},       /* front center high */
+       {"frh", SNDRV_CHMAP_FRH},       /* front right high */
+       {"tc", SNDRV_CHMAP_TC},         /* top center */
+       {"tfl", SNDRV_CHMAP_TFL},       /* top front left */
+       {"tfr", SNDRV_CHMAP_TFR},       /* top front right */
+       {"tfc", SNDRV_CHMAP_TFC},       /* top front center */
+       {"trl", SNDRV_CHMAP_TRL},       /* top rear left */
+       {"trr", SNDRV_CHMAP_TRR},       /* top rear right */
+       {"trc", SNDRV_CHMAP_TRC},       /* top rear center */
+       {"tflc", SNDRV_CHMAP_TFLC},     /* top front left center */
+       {"tfrc", SNDRV_CHMAP_TFRC},     /* top front right center */
+       {"tsl", SNDRV_CHMAP_TSL},       /* top side left */
+       {"tsr", SNDRV_CHMAP_TSR},       /* top side right */
+       {"llfe", SNDRV_CHMAP_LLFE},     /* left LFE */
+       {"rlfe", SNDRV_CHMAP_RLFE},     /* right LFE */
+       {"bc", SNDRV_CHMAP_BC},         /* bottom center */
+       {"blc", SNDRV_CHMAP_BLC},       /* bottom left center */
+       {"brc", SNDRV_CHMAP_BRC},       /* bottom right center */
+};
+
+
+static int lookup_channel(const char *c)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(channel_map); i++) {
+               if (strcasecmp(channel_map[i].name, c) == 0) {
+                       return channel_map[i].id;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/* Parse a channel mapping. */
+int tplg_parse_channel(snd_tplg_t *tplg,
+       snd_config_t *cfg, void *private)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       struct snd_soc_tplg_channel *channel = private;
+       const char *id, *value;
+
+       if (tplg->channel_idx >= SND_SOC_TPLG_MAX_CHAN)
+               return -EINVAL;
+
+       channel += tplg->channel_idx;
+       snd_config_get_id(cfg, &id);
+       tplg_dbg("\tChannel %s at index %d\n", id, tplg->channel_idx);
+
+       channel->id = lookup_channel(id);
+       if (channel->id < 0) {
+               SNDERR("error: invalid channel %s\n", id);
+               return -EINVAL;
+       }
+
+       channel->size = sizeof(*channel);
+       tplg_dbg("\tChan %s = %d\n", id, channel->id);
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+
+               /* get id */
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* get value */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               if (strcmp(id, "reg") == 0)
+                       channel->reg = atoi(value);
+               else if (strcmp(id, "shift") == 0)
+                       channel->shift = atoi(value);
+
+               tplg_dbg("\t\t%s = %s\n", id, value);
+       }
+
+       tplg->channel_idx++;
+       return 0;
+}
-- 
2.5.0

++++++ 0044-topology-Add-binary-file-builder.patch ++++++
>From 1d1dff56767842a99d2e06a6997079c0516dec68 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:22 +0100
Subject: [PATCH 44/49] topology: Add binary file builder.

Build the binary output file from all the locally parsed objects and elements.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/builder.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 327 insertions(+)
 create mode 100644 src/topology/builder.c

diff --git a/src/topology/builder.c b/src/topology/builder.c
new file mode 100644
index 000000000000..0066b220353c
--- /dev/null
+++ b/src/topology/builder.c
@@ -0,0 +1,327 @@
+/*
+  Copyright(c) 2014-2015 Intel Corporation
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  Authors: Mengdong Lin <[email protected]>
+           Yao Jin <[email protected]>
+           Liam Girdwood <[email protected]>
+*/
+
+#include "list.h"
+#include "tplg_local.h"
+
+/* verbose output detailing each object size and file position */
+static void verbose(snd_tplg_t *tplg, const char *fmt, ...)
+{
+       int offset;
+       va_list va;
+
+       if (!tplg->verbose)
+               return;
+
+       offset = lseek(tplg->out_fd, 0, SEEK_CUR);
+
+       va_start(va, fmt);
+       fprintf(stdout, "0x%6.6x/%6.6d -", offset, offset);
+       vfprintf(stdout, fmt, va);
+       va_end(va);
+}
+
+/* write out block header to output file */
+static int write_block_header(snd_tplg_t *tplg, unsigned int type,
+       unsigned int vendor_type, unsigned int version, unsigned int index,
+       size_t payload_size, int count)
+{
+       struct snd_soc_tplg_hdr hdr;
+       size_t bytes;
+       int offset = lseek(tplg->out_fd, 0, SEEK_CUR);
+
+       memset(&hdr, 0, sizeof(hdr));
+       hdr.magic = SND_SOC_TPLG_MAGIC;
+       hdr.abi = SND_SOC_TPLG_ABI_VERSION;
+       hdr.type = type;
+       hdr.vendor_type = vendor_type;
+       hdr.version = version;
+       hdr.payload_size = payload_size;
+       hdr.index = index;
+       hdr.size = sizeof(hdr);
+       hdr.count = count;
+
+       /* make sure file offset is aligned with the calculated HDR offset */
+       if ((unsigned int)offset != tplg->next_hdr_pos) {
+               SNDERR("error: New header is at offset 0x%x but file"
+                       " offset 0x%x is %s by %d bytes\n",
+                       tplg->next_hdr_pos, offset,
+                       (unsigned int)offset > tplg->next_hdr_pos ? "ahead" : 
"behind",
+                       abs(offset - tplg->next_hdr_pos));
+               exit(-EINVAL);
+       }
+
+       verbose(tplg, " header type %d size 0x%lx/%ld vendor %d "
+               "version %d\n", type, (long unsigned int)payload_size,
+               (long int)payload_size, vendor_type, version);
+
+       tplg->next_hdr_pos += hdr.payload_size + sizeof(hdr);
+
+       bytes = write(tplg->out_fd, &hdr, sizeof(hdr));
+       if (bytes != sizeof(hdr)) {
+               SNDERR("error: can't write section header %lu\n",
+                       (long unsigned int)bytes);
+               return bytes;
+       }
+
+       return bytes;
+}
+
+static int write_data_block(snd_tplg_t *tplg, int size, int tplg_type,
+       const char *obj_name, void *data)
+{
+       int ret;
+
+       /* write the header for this block */
+       ret = write_block_header(tplg, tplg_type, 0,
+               SND_SOC_TPLG_ABI_VERSION, 0, size, 1);
+       if (ret < 0) {
+               SNDERR("error: failed to write %s block %d\n", obj_name, ret);
+               return ret;
+       }
+
+       verbose(tplg, " %s : write %d bytes\n", obj_name, size);
+
+       ret = write(tplg->out_fd, data, size);
+       if (ret < 0) {
+               SNDERR("error: failed to write %s %d\n", obj_name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int write_elem_block(snd_tplg_t *tplg,
+       struct list_head *base, int size, int tplg_type, const char *obj_name)
+{
+       struct list_head *pos;
+       struct tplg_elem *elem;
+       int ret, wsize = 0, count = 0, vendor_type;
+
+       /* count number of elements */
+       list_for_each(pos, base)
+               count++;
+
+       /* write the header for this block */
+       list_for_each(pos, base) {
+               elem = list_entry(pos, struct tplg_elem, list);
+               vendor_type = elem->vendor_type;
+               break;
+       }
+
+       ret = write_block_header(tplg, tplg_type, vendor_type,
+               SND_SOC_TPLG_ABI_VERSION, 0, size, count);
+       if (ret < 0) {
+               SNDERR("error: failed to write %s block %d\n",
+                       obj_name, ret);
+               return ret;
+       }
+
+       /* write each elem to block */
+       list_for_each(pos, base) {
+
+               elem = list_entry(pos, struct tplg_elem, list);
+
+               /* compound elems have already been copied to other elems */
+               if (elem->compound_elem)
+                       continue;
+
+               if (elem->type != OBJECT_TYPE_DAPM_GRAPH)
+                       verbose(tplg, " %s '%s': write %d bytes\n",
+                               obj_name, elem->id, elem->size);
+               else
+                       verbose(tplg, " %s '%s': write %d bytes\n",
+                               obj_name, elem->route->source, elem->size);
+
+               count = write(tplg->out_fd, elem->obj, elem->size);
+               if (count < 0) {
+                       SNDERR("error: failed to write %s %d\n",
+                               obj_name, ret);
+                       return ret;
+               }
+
+               wsize += count;
+       }
+
+       /* make sure we have written the correct size */
+       if (wsize != size) {
+               SNDERR("error: size mismatch. Expected %d wrote %d\n",
+                       size, wsize);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int calc_block_size(struct list_head *base)
+{
+       struct list_head *pos;
+       struct tplg_elem *elem;
+       int size = 0;
+
+       list_for_each(pos, base) {
+
+               elem = list_entry(pos, struct tplg_elem, list);
+
+               /* compound elems have already been copied to other elems */
+               if (elem->compound_elem)
+                       continue;
+
+               size += elem->size;
+       }
+
+       return size;
+}
+
+static int write_block(snd_tplg_t *tplg, struct list_head *base,
+       int type)
+{
+       int size;
+
+       /* calculate the block size in bytes for all elems in this list */
+       size = calc_block_size(base);
+       if (size <= 0)
+               return size;
+
+       verbose(tplg, " block size for type %d is %d\n", type, size);
+
+       /* write each elem for this block */
+       switch (type) {
+       case OBJECT_TYPE_MIXER:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_MIXER, "mixer");
+       case OBJECT_TYPE_BYTES:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_BYTES, "bytes");
+       case OBJECT_TYPE_ENUM:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_ENUM, "enum");
+       case OBJECT_TYPE_DAPM_GRAPH:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_DAPM_GRAPH, "route");
+       case OBJECT_TYPE_DAPM_WIDGET:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_DAPM_WIDGET, "widget");
+       case OBJECT_TYPE_PCM:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_PCM, "pcm");
+       case OBJECT_TYPE_BE:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_DAI_LINK, "be");
+       case OBJECT_TYPE_CC:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_DAI_LINK, "cc");
+       case OBJECT_TYPE_MANIFEST:
+               return write_data_block(tplg, size, SND_SOC_TPLG_TYPE_MANIFEST,
+                       "manifest", &tplg->manifest);
+       case OBJECT_TYPE_DATA:
+               return write_elem_block(tplg, base, size,
+                       SND_SOC_TPLG_TYPE_PDATA, "data");
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int tplg_write_data(snd_tplg_t *tplg)
+{
+       int ret;
+
+       /* write manifest */
+       ret = write_data_block(tplg, sizeof(tplg->manifest),
+               OBJECT_TYPE_MANIFEST, "manifest", &tplg->manifest);
+       if (ret < 0) {
+               SNDERR("failed to write manifest %d\n", ret);
+               return ret;
+       }
+
+       /* write mixer elems. */
+       ret = write_block(tplg, &tplg->mixer_list,
+               OBJECT_TYPE_MIXER);
+       if (ret < 0) {
+               SNDERR("failed to write control elems %d\n", ret);
+               return ret;
+       }
+
+       /* write enum control elems. */
+       ret = write_block(tplg, &tplg->enum_list,
+               OBJECT_TYPE_ENUM);
+       if (ret < 0) {
+               SNDERR("failed to write control elems %d\n", ret);
+               return ret;
+       }
+
+       /* write bytes extended control elems. */
+       ret = write_block(tplg, &tplg->bytes_ext_list,
+               OBJECT_TYPE_BYTES);
+       if (ret < 0) {
+               SNDERR("failed to write control elems %d\n", ret);
+               return ret;
+       }
+
+       /* write widget elems */
+       ret = write_block(tplg, &tplg->widget_list,
+               OBJECT_TYPE_DAPM_WIDGET);
+       if (ret < 0) {
+               SNDERR("failed to write widget elems %d\n", ret);
+               return ret;
+       }
+
+       /* write pcm elems */
+       ret = write_block(tplg, &tplg->pcm_list,
+               OBJECT_TYPE_PCM);
+       if (ret < 0) {
+               SNDERR("failed to write pcm elems %d\n", ret);
+               return ret;
+       }
+
+       /* write be elems */
+       ret = write_block(tplg, &tplg->be_list,
+               OBJECT_TYPE_BE);
+       if (ret < 0) {
+               SNDERR("failed to write be elems %d\n", ret);
+               return ret;
+       }
+
+       /* write cc elems */
+       ret = write_block(tplg, &tplg->cc_list,
+               OBJECT_TYPE_CC);
+       if (ret < 0) {
+               SNDERR("failed to write cc elems %d\n", ret);
+               return ret;
+       }
+
+       /* write route elems */
+       ret = write_block(tplg, &tplg->route_list,
+               OBJECT_TYPE_DAPM_GRAPH);
+       if (ret < 0) {
+               SNDERR("failed to write graph elems %d\n", ret);
+               return ret;
+       }
+
+       /* write private data */
+       ret = write_block(tplg, &tplg->pdata_list,
+               OBJECT_TYPE_DATA);
+       if (ret < 0) {
+               SNDERR("failed to write private data %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
-- 
2.5.0

++++++ 0045-topology-autotools-Add-build-support-for-topology-co.patch ++++++
>From fec1e8f25374ec8eb4d57ee43e94e9689a748678 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:23 +0100
Subject: [PATCH 45/49] topology: autotools: Add build support for topology
 core

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 configure.ac             |  9 ++++++++-
 include/Makefile.am      |  4 ++++
 src/Makefile.am          |  7 +++++++
 src/topology/Makefile.am | 19 +++++++++++++++++++
 4 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 src/topology/Makefile.am

diff --git a/configure.ac b/configure.ac
index 9621d4e9ec2b..b6bea2dca434 100644
--- a/configure.ac
+++ b/configure.ac
@@ -380,6 +380,9 @@ AC_ARG_ENABLE(seq,
 AC_ARG_ENABLE(ucm,
   AS_HELP_STRING([--disable-ucm], [disable the use-case-manager component]),
   [build_ucm="$enableval"], [build_ucm="yes"])
+AC_ARG_ENABLE(topology,
+  AS_HELP_STRING([--disable-topology], [disable the DSP topology component]),
+  [build_topology="$enableval"], [build_topology="yes"])
 AC_ARG_ENABLE(alisp,
   AS_HELP_STRING([--disable-alisp], [disable the alisp component]),
   [build_alisp="$enableval"], [build_alisp="yes"])
@@ -422,6 +425,7 @@ AM_CONDITIONAL([BUILD_RAWMIDI], [test x$build_rawmidi = 
xyes])
 AM_CONDITIONAL([BUILD_HWDEP], [test x$build_hwdep = xyes])
 AM_CONDITIONAL([BUILD_SEQ], [test x$build_seq = xyes])
 AM_CONDITIONAL([BUILD_UCM], [test x$build_ucm = xyes])
+AM_CONDITIONAL([BUILD_TOPOLOGY], [test x$build_topology = xyes])
 AM_CONDITIONAL([BUILD_ALISP], [test x$build_alisp = xyes])
 AM_CONDITIONAL([BUILD_PYTHON], [test x$build_python = xyes])
 
@@ -443,6 +447,9 @@ fi
 if test "$build_ucm" = "yes"; then
   AC_DEFINE([BUILD_UCM], "1", [Build UCM component])
 fi
+if test "$build_topology" = "yes"; then
+  AC_DEFINE([BUILD_TOPOLOGY], "1", [Build DSP Topology component])
+fi
 
 dnl PCM Plugins
 
@@ -643,7 +650,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile 
doc/doxygen.cfg \
          src/pcm/Makefile src/pcm/scopes/Makefile \
          src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
-          src/alisp/Makefile \
+          src/alisp/Makefile src/topology/Makefile \
          src/conf/Makefile src/conf/alsa.conf.d/Makefile \
          src/conf/cards/Makefile \
          src/conf/pcm/Makefile \
diff --git a/include/Makefile.am b/include/Makefile.am
index 4baa03af69e1..ff931fda24d5 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -50,6 +50,10 @@ if BUILD_UCM
 alsainclude_HEADERS += use-case.h
 endif
 
+if BUILD_TOPOLOGY
+alsainclude_HEADERS += topology.h
+endif
+
 if BUILD_ALISP
 alsainclude_HEADERS += alisp.h
 endif
diff --git a/src/Makefile.am b/src/Makefile.am
index fa255ff43ee0..57686a612fd8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,6 +42,10 @@ if BUILD_UCM
 SUBDIRS += ucm
 libasound_la_LIBADD += ucm/libucm.la
 endif
+if BUILD_TOPOLOGY
+SUBDIRS += topology
+libasound_la_LIBADD += topology/libtopology.la
+endif
 if BUILD_ALISP
 SUBDIRS += alisp
 libasound_la_LIBADD += alisp/libalisp.la
@@ -81,6 +85,9 @@ seq/libseq.la:
 ucm/libucm.la:
        $(MAKE) -C ucm libucm.la
 
+topology/libtopology.la:
+       $(MAKE) -C topology libtopology.la
+
 instr/libinstr.la:
        $(MAKE) -C instr libinstr.la
 
diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am
new file mode 100644
index 000000000000..3fb8bf7a9290
--- /dev/null
+++ b/src/topology/Makefile.am
@@ -0,0 +1,19 @@
+EXTRA_LTLIBRARIES = libtopology.la
+
+libtopology_la_SOURCES =\
+       parser.c \
+       builder.c \
+       ctl.c \
+       dapm.c \
+       pcm.c \
+       data.c \
+       text.c \
+       channel.c \
+       ops.c \
+       elem.c
+
+noinst_HEADERS = tplg_local.h
+
+all: libtopology.la
+
+AM_CPPFLAGS=-I$(top_srcdir)/include
-- 
2.5.0

++++++ 0046-topology-doxygen-Add-doxygen-support-for-topology-co.patch ++++++
>From 22603237b09ed50744030f550248ade135d4f73b Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:24 +0100
Subject: [PATCH 46/49] topology: doxygen: Add doxygen support for topology
 core.

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 doc/doxygen.cfg.in | 7 +++++--
 doc/index.doxygen  | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
index 043e75b2d7eb..92bd52ba67a2 100644
--- a/doc/doxygen.cfg.in
+++ b/doc/doxygen.cfg.in
@@ -29,6 +29,7 @@ INPUT            = @top_srcdir@/doc/index.doxygen \
                   @top_srcdir@/include/control_external.h \
                   @top_srcdir@/include/mixer.h \
                   @top_srcdir@/include/use-case.h \
+                  @top_srcdir@/include/topology.h \
                   @top_srcdir@/src/error.c \
                   @top_srcdir@/src/dlmisc.c \
                   @top_srcdir@/src/async.c \
@@ -78,7 +79,8 @@ INPUT            = @top_srcdir@/doc/index.doxygen \
                   @top_srcdir@/src/timer \
                   @top_srcdir@/src/hwdep \
                   @top_srcdir@/src/seq \
-                  @top_srcdir@/src/ucm
+                  @top_srcdir@/src/ucm \
+                  @top_srcdir@/src/topology
 EXCLUDE                 = @top_srcdir@/src/control/control_local.h \
                   @top_srcdir@/src/pcm/atomic.h \
                   @top_srcdir@/src/pcm/interval.h \
@@ -94,7 +96,8 @@ EXCLUDE                = 
@top_srcdir@/src/control/control_local.h \
                   @top_srcdir@/src/mixer/mixer_local.h \
                   @top_srcdir@/src/rawmidi/rawmidi_local.h \
                   @top_srcdir@/src/seq/seq_local.h \
-                  @top_srcdir@/src/ucm/ucm_local.h
+                  @top_srcdir@/src/ucm/ucm_local.h \
+                  @top_srcdir@/src/topology/tplg_local.h
 RECURSIVE       = YES
 FILE_PATTERNS    = *.c *.h
 EXAMPLE_PATH     = @top_srcdir@/test
diff --git a/doc/index.doxygen b/doc/index.doxygen
index 7d049fe5c32a..b40c75a5239b 100644
--- a/doc/index.doxygen
+++ b/doc/index.doxygen
@@ -41,6 +41,7 @@ may be placed in the library code instead of the kernel 
driver.</P>
   <LI>Page \ref timer explains the design of the Timer API.
   <LI>Page \ref seq explains the design of the Sequencer API.
   <LI>Page \ref ucm explains the use case API.
+  <LI>Page \ref topology explains the DSP topology API.
 </UL>
 
 <H2>Configuration</H2>
-- 
2.5.0

++++++ 0047-conf-topology-Add-topology-file-for-broadwell-audio-.patch ++++++
>From 00a51b5bacb0f966d0e323bd9d3057c0eb0e6f23 Mon Sep 17 00:00:00 2001
From: Liam Girdwood <[email protected]>
Date: Wed, 29 Jul 2015 17:45:25 +0100
Subject: [PATCH 47/49] conf: topology: Add topology file for broadwell audio
 DSP

Signed-off-by: Liam Girdwood <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
---
 configure.ac                               |   2 +
 src/conf/Makefile.am                       |   2 +-
 src/conf/topology/Makefile.am              |   1 +
 src/conf/topology/broadwell/Makefile.am    |   4 +
 src/conf/topology/broadwell/broadwell.conf | 375 +++++++++++++++++++++++++++++
 5 files changed, 383 insertions(+), 1 deletion(-)
 create mode 100644 src/conf/topology/Makefile.am
 create mode 100644 src/conf/topology/broadwell/Makefile.am
 create mode 100644 src/conf/topology/broadwell/broadwell.conf

diff --git a/configure.ac b/configure.ac
index b6bea2dca434..a482b3e7f6ca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -663,6 +663,8 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile 
doc/doxygen.cfg \
          src/conf/ucm/PAZ00/Makefile \
          src/conf/ucm/GoogleNyan/Makefile \
          src/conf/ucm/broadwell-rt286/Makefile \
+         src/conf/topology/Makefile \
+         src/conf/topology/broadwell/Makefile \
          modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile 
\
          alsalisp/Makefile aserver/Makefile \
          test/Makefile test/lsb/Makefile \
diff --git a/src/conf/Makefile.am b/src/conf/Makefile.am
index 948d5a1c822e..a04f73fddc65 100644
--- a/src/conf/Makefile.am
+++ b/src/conf/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=cards pcm alsa.conf.d ucm
+SUBDIRS=cards pcm alsa.conf.d ucm topology
 
 cfg_files = alsa.conf
 if BUILD_ALISP
diff --git a/src/conf/topology/Makefile.am b/src/conf/topology/Makefile.am
new file mode 100644
index 000000000000..f56a96c651e5
--- /dev/null
+++ b/src/conf/topology/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=broadwell
diff --git a/src/conf/topology/broadwell/Makefile.am 
b/src/conf/topology/broadwell/Makefile.am
new file mode 100644
index 000000000000..35d1e83cb645
--- /dev/null
+++ b/src/conf/topology/broadwell/Makefile.am
@@ -0,0 +1,4 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+topologydir = $(alsaconfigdir)/topology/broadwell
+topology_DATA = broadwell.conf
+EXTRA_DIST = $(topology_DATA)
diff --git a/src/conf/topology/broadwell/broadwell.conf 
b/src/conf/topology/broadwell/broadwell.conf
new file mode 100644
index 000000000000..05b3889bec58
--- /dev/null
+++ b/src/conf/topology/broadwell/broadwell.conf
@@ -0,0 +1,375 @@
+# Dynamic Firmware Configuration for Broadwell
+
+# TLV
+SectionTLV."hsw_vol_tlv" {
+       Comment "TLV used by both global and stream volumes"
+
+       scale {
+               min "-9000"
+               step "300"
+               mute "1"
+       }
+}
+
+# Controls
+SectionControlMixer."Master Playback Volume" {
+       Comment "Global DSP volume"
+
+       # control belongs to this index group
+       index "1"
+
+       # Channel register and shift for Front Left/Right
+       channel."FL" {
+               reg "0"
+               shift "0"
+       }
+       channel."FR" {
+               reg "0"
+               shift "8"
+       }
+
+       # max control value and whether value is inverted
+       max "31"
+       invert "false"
+
+       # control uses bespoke driver get/put/info ID 0
+       ops."ctl" {
+               info "volsw"
+               get "256"
+               put "256"
+       }
+
+       # uses TLV data above
+       tlv "hsw_vol_tlv"
+}
+
+SectionControlMixer."Media0 Playback Volume" {
+       Comment "Offload 0 volume"
+
+       # control belongs to this index group
+       index "1"
+
+       # Channel register and shift for Front Left/Right
+       channel."FL" {
+               reg "1"
+               shift "0"
+       }
+       channel."FR" {
+               reg "1"
+               shift "8"
+       }
+
+       # max control value and whether value is inverted
+       max "31"
+       invert "false"
+
+       # control uses bespoke driver get/put/info ID 0
+       ops."ctl" {
+               info "volsw"
+               get "257"
+               put "257"
+       }
+
+       # uses TLV data above
+       tlv "hsw_vol_tlv"
+}
+
+SectionControlMixer."Media1 Playback Volume" {
+       Comment "Offload 1 volume"
+
+       # control belongs to this index group
+       index "1"
+
+       # Channel register and shift for Front Left/Right
+       channel."FL" {
+               reg "2"
+               shift "0"
+       }
+       channel."FR" {
+               reg "2"
+               shift "8"
+       }
+
+       # max control value and whether value is inverted
+       max "31"
+       invert "false"
+
+       # control uses bespoke driver get/put/info ID 0
+       ops."ctl" {
+               info "volsw"
+               get "257"
+               put "257"
+       }
+
+       # uses TLV data above
+       tlv "hsw_vol_tlv"
+}
+
+SectionControlMixer."Mic Capture Volume" {
+       Comment "Mic Capture volume"
+
+       # control belongs to this index group
+       index "1"
+
+       # Channel register and shift for Front Left/Right
+       channel."FL" {
+               reg "0"
+               shift "0"
+       }
+       channel."FR" {
+               reg "0"
+               shift "8"
+       }
+
+       # max control value and whether value is inverted
+       max "31"
+       invert "false"
+
+       # control uses bespoke driver get/put/info ID 0
+       ops."ctl" {
+               info "volsw"
+               get "257"
+               put "257"
+       }
+
+       # uses TLV data above
+       tlv "hsw_vol_tlv"
+}
+
+SectionWidget."SSP0 CODEC IN" {
+
+       index "1"
+       type "aif_in"
+       no_pm "true"
+       shift "0"
+       invert "0"
+}
+
+SectionWidget."SSP0 CODEC OUT" {
+
+       index "1"
+       type "aif_out"
+       no_pm "true"
+       shift "0"
+       invert "0"
+}
+
+SectionWidget."SSP1 BT IN" {
+
+       index "1"
+       type "aif_in"
+       no_pm "true"
+       shift "0"
+       invert "0"
+}
+
+SectionWidget."SSP1 BT OUT" {
+
+       index "1"
+       type "aif_out"
+       no_pm "true"
+       shift "0"
+       invert "0"
+}
+
+SectionWidget."Playback VMixer" {
+
+       index "1"
+       type "mixer"
+       no_pm "true"
+       shift "0"
+       invert "0"
+}
+
+# PCM Configurations supported by FW
+SectionPCMConfig."PCM 48k Stereo 24bit" {
+
+       config."playback" {
+               format "S24_LE"
+               rate "48000"
+               channels "2"
+               tdm_slot "0xf"
+       }
+
+       config."capture" {
+               format "S24_LE"
+               rate "48000"
+               channels "2"
+               tdm_slot "0xf"
+       }
+}
+
+SectionPCMConfig."PCM 48k Stereo 16bit" {
+
+       config."playback" {
+               format "S16_LE"
+               rate "48000"
+               channels "2"
+               tdm_slot "0xf"
+       }
+
+       config."capture" {
+               format "S16_LE"
+               rate "48000"
+               channels "2"
+               tdm_slot "0xf"
+       }
+}
+
+SectionPCMConfig."PCM 48k 2P/4C 16bit" {
+
+       config."playback" {
+               format "S16_LE"
+               rate "48000"
+               channels "2"
+               tdm_slot "0xf"
+       }
+
+       config."capture" {
+               format "S16_LE"
+               rate "48000"
+               channels "4"
+               tdm_slot "0xf"
+       }
+}
+
+# PCM capabilities supported by FW
+SectionPCMCapabilities."System Playback" {
+
+       formats "S24_LE,S16_LE"
+       rate_min "48000"
+       rate_max "48000"
+       channels_min "2"
+       channels_max "2"
+}
+
+SectionPCMCapabilities."Analog Capture" {
+
+       formats "S24_LE,S16_LE"
+       rate_min "48000"
+       rate_max "48000"
+       channels_min "2"
+       channels_max "4"
+}
+
+SectionPCMCapabilities."Loopback Capture" {
+
+       formats "S24_LE,S16_LE"
+       rate_min "48000"
+       rate_max "48000"
+       channels_min "2"
+       channels_max "2"
+}
+
+SectionPCMCapabilities."Offload0 Playback" {
+       formats "S24_LE,S16_LE"
+       rate_min "8000"
+       rate_max "192000"
+       channels_min "2"
+       channels_max "2"
+}
+
+SectionPCMCapabilities."Offload1 Playback" {
+       formats "S24_LE,S16_LE"
+       rate_min "8000"
+       rate_max "48000"
+       channels_min "2"
+       channels_max "2"
+}
+
+# PCM devices exported by Firmware
+SectionPCM."System Pin" {
+
+       index "1"
+
+       # used for binding to the PCM
+       ID "0"
+
+       pcm."playback" {
+
+               capabilities "System Playback"
+
+               configs [
+                       "PCM 48k Stereo 24bit"
+                       "PCM 48k Stereo 16bit"
+               ]
+       }
+
+       pcm."capture" {
+
+               capabilities "Analog Capture"
+
+               configs [
+                       "PCM 48k Stereo 24bit"
+                       "PCM 48k Stereo 16bit"
+                       "PCM 48k 2P/4C 16bit"
+               ]
+       }
+}
+
+SectionPCM."Offload0 Pin" {
+
+       index "1"
+
+       # used for binding to the PCM
+       ID "1"
+
+       pcm."playback" {
+
+               capabilities "Offload0 Playback"
+
+               configs [
+                       "PCM 48k Stereo 24bit"
+                       "PCM 48k Stereo 16bit"
+               ]
+       }
+}
+
+SectionPCM."Offload1 Pin" {
+
+       index "1"
+
+       # used for binding to the PCM
+       ID "2"
+
+       pcm."playback" {
+
+               capabilities "Offload1 Playback"
+
+               configs [
+                       "PCM 48k Stereo 24bit"
+                       "PCM 48k Stereo 16bit"
+               ]
+       }
+}
+
+SectionPCM."Loopback Pin" {
+
+       index "1"
+
+       # used for binding to the PCM
+       ID "3"
+
+       pcm."capture" {
+
+               capabilities "Loopback Capture"
+
+               configs [
+                       "PCM 48k Stereo 24bit"
+                       "PCM 48k Stereo 16bit"
+               ]
+       }
+}
+
+SectionGraph."dsp" {
+       index "1"
+
+       lines [
+               "Playback VMixer, , System Playback"
+               "Playback VMixer, , Offload0 Playback"
+               "Playback VMixer, , Offload1 Playback"
+               "SSP0 CODEC OUT, , Playback VMixer"
+               "Loopback Capture, , Playback VMixer"
+               "Analog Capture, , SSP0 CODEC IN"
+       ]
+}
-- 
2.5.0

++++++ 0048-topology-Fix-missing-inclusion-of-ctype.h.patch ++++++
>From 907e464593a2acf51c2e2be4c3d4e098efdd95ff Mon Sep 17 00:00:00 2001
From: Takashi Iwai <[email protected]>
Date: Thu, 30 Jul 2015 16:34:50 +0200
Subject: [PATCH 48/49] topology: Fix missing inclusion of ctype.h

Fix a compile warning:
  data.c:116:7: warning: implicit declaration of function 'isspace' 
[-Wimplicit-function-declaration]

Signed-off-by: Takashi Iwai <[email protected]>
---
 src/topology/data.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/topology/data.c b/src/topology/data.c
index ae664721935d..13e1e2bb60fb 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -18,6 +18,7 @@
 
 #include "list.h"
 #include "tplg_local.h"
+#include <ctype.h>
 
 /* Get Private data from a file. */
 static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
-- 
2.5.0

++++++ 0049-topology-Fix-typos.patch ++++++
>From 66ce9f9a1177de3b8e8304323b4d3a16d78ead32 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <[email protected]>
Date: Thu, 30 Jul 2015 16:43:19 +0200
Subject: [PATCH 49/49] topology: Fix typos

Signed-off-by: Takashi Iwai <[email protected]>
---
 include/topology.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/topology.h b/include/topology.h
index f604ed1450d3..0cb2d79e5574 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -48,7 +48,7 @@ extern "C" {
  *
  * The topology text format uses the standard ALSA configuration file format to
  * describe each topology object type. This allows topology objects to include
- * other topology objects as part of thier definition. i.e. a TLV data object
+ * other topology objects as part of their definition. i.e. a TLV data object
  * can be shared amongst many control objects that use the same TLV data.
  *
  *
@@ -174,7 +174,7 @@ extern "C" {
  *     words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
  * };
  * </pre>
- * The file, bytes, shorts and words keywords are all mutulally exclusive as
+ * The file, bytes, shorts and words keywords are all mutually exclusive as
  * the private data should only be taken from one source.  The private data can
  * either be read from a separate file or defined in the topology file using
  * the bytes, shorts or words keywords.
@@ -247,7 +247,7 @@ extern "C" {
  * can include channel mapping, callback operations, private data and
  * text strings to represent the enumerated control options.<br>
  *
- * The text strings for the enumerated controls are defined in a seperate
+ * The text strings for the enumerated controls are defined in a separate
  * section as follows :-
  *
  * <pre>
@@ -306,7 +306,7 @@ extern "C" {
  * graph with other graphs, it's not used by the kernel atm.
  *
  * <h4>DAPM Widgets</h4>
- * DAPM wigets are similar to controls in that they can include many other
+ * DAPM widgets are similar to controls in that they can include many other
  * objects. Widgets can contain private data, mixer controls and enum controls.
  *
  * The following widget types are supported and match the driver types :-
@@ -367,13 +367,13 @@ extern "C" {
  *
  *     formats "S24_LE,S16_LE"         # Supported formats
  *     rate_min "48000"                # Max supported sample rate
- *     rate_max "48000"                # Min suppoprted sample rate
+ *     rate_max "48000"                # Min supported sample rate
  *     channels_min "2"                # Min number of channels
  *     channels_max "2"                # max number of channels
  * }
  * </pre>
  * The supported formats use the same naming convention as the driver macros.
- * The PCM capabilities name can be reffered to and included by BE, PCM and
+ * The PCM capabilities name can be referred to and included by BE, PCM and
  * Codec <-> codec topology sections.
  *
  * <h4>PCM Configurations</h4>
@@ -400,7 +400,7 @@ extern "C" {
  * </pre>
  *
  * The supported formats use the same naming convention as the driver macros.
- * The PCM configuration name can be reffered to and included by BE, PCM and
+ * The PCM configuration name can be referred to and included by BE, PCM and
  * Codec <-> codec topology sections.
  *
  * <h4>PCM Configurations</h4>
@@ -434,7 +434,7 @@ extern "C" {
  *     id "0"                          # used for binding to the PCM
  *
  *     pcm."playback" {
- *             capabilities "capabilities1"    # capbilities for playback
+ *             capabilities "capabilities1"    # capabilities for playback
  *
  *             configs [               # supported configs for playback
  *                     "config1"
@@ -476,7 +476,7 @@ void snd_tplg_free(snd_tplg_t *tplg);
  * \param tplg Topology instance.
  * \param infile Topology text input file to be parsed
  * \param outfile Binary topology output file.
- * \return Zero on sucess, otherwise a negative error code
+ * \return Zero on success, otherwise a negative error code
  */
 int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile,
        const char *outfile);
-- 
2.5.0





Reply via email to