Blob Blame History Raw
From 7c424edd116e76eee6218a1e9a6ff6c4daaf2a4d Mon Sep 17 00:00:00 2001
From: Shengjiu Wang <shengjiu.wang@freescale.com>
Date: Wed, 6 Apr 2016 19:02:12 +0800
Subject: [PATCH 01/34] pcm_plugin: fix appl pointer not correct when
 mmap_commit() return error

When snd_pcm_mmap_commit() return error, the appl pointer is also updated.
which cause the avail_update()'s result wrong.
This patch move the snd_pcm_mmap_appl_forward() to the place when
snd_pcm_mmap_commit() is successfully returned.

Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_plugin.c | 48 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index d007e8c..940491d 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -279,18 +279,22 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 			return -EPIPE;
 		}
 		snd_atomic_write_begin(&plugin->watom);
-		snd_pcm_mmap_appl_forward(pcm, frames);
 		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 			snd_pcm_sframes_t res;
 			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
-			if (res < 0)
+			if (res < 0) {
+				snd_atomic_write_end(&plugin->watom);
 				return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+			}
 			frames -= res;
 		}
-		snd_atomic_write_end(&plugin->watom);
-		if (result <= 0)
+		if (result <= 0) {
+			snd_atomic_write_end(&plugin->watom);
 			return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+		}
+		snd_pcm_mmap_appl_forward(pcm, frames);
+		snd_atomic_write_end(&plugin->watom);
 		offset += frames;
 		xfer += frames;
 		size -= frames;
@@ -325,19 +329,23 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 			return -EPIPE;
 		}
 		snd_atomic_write_begin(&plugin->watom);
-		snd_pcm_mmap_appl_forward(pcm, frames);
 		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 			snd_pcm_sframes_t res;
 			
 			res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result);
-			if (res < 0)
+			if (res < 0) {
+				snd_atomic_write_end(&plugin->watom);
 				return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+			}
 			frames -= res;
 		}
-		snd_atomic_write_end(&plugin->watom);
-		if (result <= 0)
+		if (result <= 0) {
+			snd_atomic_write_end(&plugin->watom);
 			return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+		}
+		snd_pcm_mmap_appl_forward(pcm, frames);
+		snd_atomic_write_end(&plugin->watom);
 		offset += frames;
 		xfer += frames;
 		size -= frames;
@@ -423,19 +431,23 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 		frames = plugin->write(pcm, areas, appl_offset, frames,
 				       slave_areas, slave_offset, &slave_frames);
 		snd_atomic_write_begin(&plugin->watom);
-		snd_pcm_mmap_appl_forward(pcm, frames);
 		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
-		snd_atomic_write_end(&plugin->watom);
 		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 			snd_pcm_sframes_t res;
 			
 			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
-			if (res < 0)
+			if (res < 0) {
+				snd_atomic_write_end(&plugin->watom);
 				return xfer > 0 ? xfer : res;
+			}
 			frames -= res;
 		}
-		if (result <= 0)
+		if (result <= 0) {
+			snd_atomic_write_end(&plugin->watom);
 			return xfer > 0 ? xfer : result;
+		}
+		snd_pcm_mmap_appl_forward(pcm, frames);
+		snd_atomic_write_end(&plugin->watom);
 		if (frames == cont)
 			appl_offset = 0;
 		else
@@ -490,19 +502,23 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 			frames = (plugin->read)(pcm, areas, hw_offset, frames,
 					      slave_areas, slave_offset, &slave_frames);
 			snd_atomic_write_begin(&plugin->watom);
-			snd_pcm_mmap_hw_forward(pcm, frames);
 			result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
-			snd_atomic_write_end(&plugin->watom);
 			if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 				snd_pcm_sframes_t res;
 				
 				res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result);
-				if (res < 0)
+				if (res < 0) {
+					snd_atomic_write_end(&plugin->watom);
 					return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+				}
 				frames -= res;
 			}
-			if (result <= 0)
+			if (result <= 0) {
+				snd_atomic_write_end(&plugin->watom);
 				return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+			}
+			snd_pcm_mmap_hw_forward(pcm, frames);
+			snd_atomic_write_end(&plugin->watom);
 			if (frames == cont)
 				hw_offset = 0;
 			else
-- 
2.5.5

From 503a285ed60164d8c65c6ee9ba6f23631da753df Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 7 Apr 2016 16:29:41 +0200
Subject: [PATCH 02/34] pcm: Clean up error paths in snd_pcm_plugin_*() helpers

Minor code refactoring to unify the error return paths.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_plugin.c | 67 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 22 deletions(-)

diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index 940491d..8527783 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -276,7 +276,8 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 		if (CHECK_SANITY(slave_frames > snd_pcm_mmap_playback_avail(slave))) {
 			SNDMSG("write overflow %ld > %ld", slave_frames,
 			       snd_pcm_mmap_playback_avail(slave));
-			return -EPIPE;
+			err = -EPIPE;
+			goto error;
 		}
 		snd_atomic_write_begin(&plugin->watom);
 		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
@@ -284,14 +285,14 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 			snd_pcm_sframes_t res;
 			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
 			if (res < 0) {
-				snd_atomic_write_end(&plugin->watom);
-				return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+				err = res;
+				goto error_atomic;
 			}
 			frames -= res;
 		}
 		if (result <= 0) {
-			snd_atomic_write_end(&plugin->watom);
-			return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+			err = result;
+			goto error_atomic;
 		}
 		snd_pcm_mmap_appl_forward(pcm, frames);
 		snd_atomic_write_end(&plugin->watom);
@@ -300,6 +301,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 		size -= frames;
 	}
 	return (snd_pcm_sframes_t)xfer;
+
+ error_atomic:
+	snd_atomic_write_end(&plugin->watom);
+ error:
+	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
 static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
@@ -311,6 +317,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 	snd_pcm_t *slave = plugin->gen.slave;
 	snd_pcm_uframes_t xfer = 0;
 	snd_pcm_sframes_t result;
+	int err;
 	
 	while (size > 0) {
 		snd_pcm_uframes_t frames = size;
@@ -326,7 +333,8 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 		if (CHECK_SANITY(slave_frames > snd_pcm_mmap_capture_avail(slave))) {
 			SNDMSG("read overflow %ld > %ld", slave_frames,
 			       snd_pcm_mmap_playback_avail(slave));
-			return -EPIPE;
+			err = -EPIPE;
+			goto error;
 		}
 		snd_atomic_write_begin(&plugin->watom);
 		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
@@ -335,14 +343,14 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 			
 			res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result);
 			if (res < 0) {
-				snd_atomic_write_end(&plugin->watom);
-				return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+				err = res;
+				goto error_atomic;
 			}
 			frames -= res;
 		}
 		if (result <= 0) {
-			snd_atomic_write_end(&plugin->watom);
-			return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+			err = result;
+			goto error_atomic;
 		}
 		snd_pcm_mmap_appl_forward(pcm, frames);
 		snd_atomic_write_end(&plugin->watom);
@@ -351,6 +359,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 		size -= frames;
 	}
 	return (snd_pcm_sframes_t)xfer;
+
+ error_atomic:
+	snd_atomic_write_end(&plugin->watom);
+ error:
+	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
 
@@ -401,6 +414,7 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 	snd_pcm_uframes_t appl_offset;
 	snd_pcm_sframes_t slave_size;
 	snd_pcm_sframes_t xfer;
+	int err;
 
 	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 		snd_atomic_write_begin(&plugin->watom);
@@ -421,11 +435,10 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 		snd_pcm_uframes_t slave_offset;
 		snd_pcm_uframes_t slave_frames = ULONG_MAX;
 		snd_pcm_sframes_t result;
-		int err;
 
 		err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 		if (err < 0)
-			return xfer > 0 ? xfer : err;
+			goto error;
 		if (frames > cont)
 			frames = cont;
 		frames = plugin->write(pcm, areas, appl_offset, frames,
@@ -437,14 +450,14 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 			
 			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
 			if (res < 0) {
-				snd_atomic_write_end(&plugin->watom);
-				return xfer > 0 ? xfer : res;
+				err = res;
+				goto error_atomic;
 			}
 			frames -= res;
 		}
 		if (result <= 0) {
-			snd_atomic_write_end(&plugin->watom);
-			return xfer > 0 ? xfer : result;
+			err = result;
+			goto error_atomic;
 		}
 		snd_pcm_mmap_appl_forward(pcm, frames);
 		snd_atomic_write_end(&plugin->watom);
@@ -461,6 +474,11 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 		return -EPIPE;
 	}
 	return xfer;
+
+ error_atomic:
+	snd_atomic_write_end(&plugin->watom);
+ error:
+	return xfer > 0 ? xfer : err;
 }
 
 static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
@@ -468,6 +486,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 	snd_pcm_plugin_t *plugin = pcm->private_data;
 	snd_pcm_t *slave = plugin->gen.slave;
 	snd_pcm_sframes_t slave_size;
+	int err;
 
 	slave_size = snd_pcm_avail_update(slave);
 	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
@@ -492,11 +511,10 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 			snd_pcm_uframes_t slave_offset;
 			snd_pcm_uframes_t slave_frames = ULONG_MAX;
 			snd_pcm_sframes_t result;
-			int err;
 
 			err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 			if (err < 0)
-				return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
+				goto error;
 			if (frames > cont)
 				frames = cont;
 			frames = (plugin->read)(pcm, areas, hw_offset, frames,
@@ -508,14 +526,14 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 				
 				res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result);
 				if (res < 0) {
-					snd_atomic_write_end(&plugin->watom);
-					return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
+					err = res;
+					goto error_atomic;
 				}
 				frames -= res;
 			}
 			if (result <= 0) {
-				snd_atomic_write_end(&plugin->watom);
-				return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
+				err = result;
+				goto error_atomic;
 			}
 			snd_pcm_mmap_hw_forward(pcm, frames);
 			snd_atomic_write_end(&plugin->watom);
@@ -528,6 +546,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 			xfer += frames;
 		}
 		return (snd_pcm_sframes_t)xfer;
+
+	error_atomic:
+		snd_atomic_write_end(&plugin->watom);
+	error:
+		return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 	}
 }
 
-- 
2.5.5

From 374c5fa9c5cb80efa41ef8a3afd215aa48b48436 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:28:42 +0800
Subject: [PATCH 03/34] topology: Use the generic pointer to free an element's
 object

The element is a wrapper for different types of objects.So use the
generic pointer 'obj' instead of the type-specific pointer to free
the object.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/elem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/topology/elem.c b/src/topology/elem.c
index 12d6a72..00f9eea 100644
--- a/src/topology/elem.c
+++ b/src/topology/elem.c
@@ -83,8 +83,8 @@ void tplg_elem_free(struct tplg_elem *elem)
 	/* free struct snd_tplg_ object,
 	 * the union pointers share the same address
 	 */
-	if (elem->mixer_ctrl)
-		free(elem->mixer_ctrl);
+	if (elem->obj)
+		free(elem->obj);
 
 	free(elem);
 }
-- 
2.5.5

From 6b31bf8edb407f4c184576909f40c41bdc8439e4 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:01 +0800
Subject: [PATCH 04/34] topology: Define a free handler for the element

This handler is defined for type-specific destruction of an element.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/elem.c       | 6 +++++-
 src/topology/tplg_local.h | 2 ++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/topology/elem.c b/src/topology/elem.c
index 00f9eea..f2afaaf 100644
--- a/src/topology/elem.c
+++ b/src/topology/elem.c
@@ -83,8 +83,12 @@ void tplg_elem_free(struct tplg_elem *elem)
 	/* free struct snd_tplg_ object,
 	 * the union pointers share the same address
 	 */
-	if (elem->obj)
+	if (elem->obj) {
+		if (elem->free)
+			elem->free(elem->obj);
+
 		free(elem->obj);
+	}
 
 	free(elem);
 }
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 4915b1a..7368a86 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -127,6 +127,8 @@ struct tplg_elem {
 	 */
 	struct list_head ref_list;
 	struct list_head list; /* list of all elements with same type */
+
+	void (*free)(void *obj);
 };
 
 struct map_elem {
-- 
2.5.5

From 2fd8d388f530b03872d8afb51b0f98c6474646c7 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:15 +0800
Subject: [PATCH 05/34] topology: Add doc for vendor tuples

Describe how to define vendor tokens and tuples in the text conf file.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/topology.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 73 insertions(+), 4 deletions(-)

diff --git a/include/topology.h b/include/topology.h
index 011f6ae..51d282f 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -203,12 +203,77 @@ extern "C" {
  *	bytes "0x12,0x34,0x56,0x78"
  *	shorts "0x1122,0x3344,0x5566,0x7788"
  *	words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
+ *	tuples "section id of the vendor tuples"
  * };
  * </pre>
- * 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.
+ * The file, bytes, shorts, words and tuples 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, words or tuples keywords.
+ * The keyword tuples is to define vendor specific tuples. Please refer to
+ * section Vendor Tokens and Vendor tuples.
+ *
+ *  <h6>Vendor Tokens</h6>
+ * A vendor token list is defined as a new section. Each token element is
+ * a pair of string ID and integer value. And both the ID and value are
+ * vendor-specific.
+ *
+ * <pre>
+ * SectionVendorTokens."id of the vendor tokens" {
+ *	comment "optional comments"
+ *	VENDOR_TOKEN_ID1 "1"
+ *	VENDOR_TOKEN_ID2 "2"
+ *	VENDOR_TOKEN_ID3 "3"
+ *	...
+ * }
+ * </pre>
+ *
+ *  <h6>Vendor Tuples</h6>
+ * Vendor tuples are defined as a new section. It contains a reference to
+ * a vendor token list and several tuple arrays.
+ * All arrays share a vendor token list, defined by the tokens keyword.
+ * Each tuple array is for a specific type, defined by the string following
+ * the tuples keyword. Supported types are: string, uuid, bool, byte,
+ * short and word.
+ *
+ * <pre>
+ * SectionVendorTuples."id of the vendor tuples" {
+ *	tokens "id of the vendor tokens"
+ *
+ *	tuples."string" {
+ *		VENDOR_TOKEN_ID1 "character string"
+ *		...
+ *	}
+ *
+ *	tuples."uuid" {
+ *		VENDOR_TOKEN_ID2 "16 character uuid"
+ *		...
+ *	}
+ *
+ *	tuples."bool" {
+ *		VENDOR_TOKEN_ID3 "true/false"
+ *		...
+ *	}
+ *
+ *	tuples."byte" {
+ *		VENDOR_TOKEN_ID4 "0x11"
+ *		VENDOR_TOKEN_ID5 "0x22"
+ *		...
+ *	}
+ *
+ *	tuples."short" {
+ *		VENDOR_TOKEN_ID6 "0x1122"
+ *		VENDOR_TOKEN_ID7 "0x3344"
+ *		...
+ *	}
+ *
+ *	tuples."word" {
+ *		VENDOR_TOKEN_ID8 "0x11223344"
+ *		VENDOR_TOKEN_ID9 "0x55667788"
+ *		...
+ *	}
+ * }
+ * </pre>
  *
  * <h5>Mixer Controls</h5>
  * A mixer control is defined as a new section that can include channel mapping,
@@ -389,6 +454,10 @@ extern "C" {
  * fields are the same for widgets as they are for controls whilst the other
  * fields map on very closely to the driver widget fields.
  *
+ * <h5>Widget Private Data</h5>
+ * Widget can have private data. For the format of the private data, please
+ * refer to section Control Private Data.
+ *
  * <h4>PCM Capabilities</h4>
  * Topology can also define the capabilities of FE and BE PCMs. Capabilities
  * can be defined with the following section :-
-- 
2.5.5

From 768a006089fab94d5aeffd9115da3fbe951a94f8 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:27 +0800
Subject: [PATCH 06/34] topology: ABI - Define types for vendor tuples

Tuples, a pair of token and value, can be used to define vendor specific
data, for controls and widgets. This can avoid importing binary data blob
from other files.

Vendor specific tuple arrays will be embeded in the private data buffer
of a control or widget object. To be backward compatible, union is used
to define the tuple arrays in the existing private data ABI object
'struct snd_soc_tplg_private'.

Vendors need to make sure the token values defined by the topology conf
file match those defined by their driver.

Now supported tuple types are uuid, string, bool, byte, short and word.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asoc.h | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/include/sound/asoc.h b/include/sound/asoc.h
index a29c05c..920c9e0 100644
--- a/include/sound/asoc.h
+++ b/include/sound/asoc.h
@@ -107,6 +107,14 @@
 #define SND_SOC_TPLG_STREAM_PLAYBACK	0
 #define SND_SOC_TPLG_STREAM_CAPTURE	1
 
+/* vendor tuple types */
+#define SND_SOC_TPLG_TUPLE_TYPE_UUID	0
+#define SND_SOC_TPLG_TUPLE_TYPE_STRING	1
+#define SND_SOC_TPLG_TUPLE_TYPE_BOOL	2
+#define SND_SOC_TPLG_TUPLE_TYPE_BYTE	3
+#define SND_SOC_TPLG_TUPLE_TYPE_WORD	4
+#define SND_SOC_TPLG_TUPLE_TYPE_SHORT	5
+
 /*
  * Block Header.
  * This header precedes all object and object arrays below.
@@ -123,6 +131,35 @@ struct snd_soc_tplg_hdr {
 	__le32 count;		/* number of elements in block */
 } __attribute__((packed));
 
+/* vendor tuple for uuid */
+struct snd_soc_tplg_vendor_uuid_elem {
+	__le32 token;
+	char uuid[16];
+} __attribute__((packed));
+
+/* vendor tuple for a bool/byte/short/word value */
+struct snd_soc_tplg_vendor_value_elem {
+	__le32 token;
+	__le32 value;
+} __attribute__((packed));
+
+/* vendor tuple for string */
+struct snd_soc_tplg_vendor_string_elem {
+	__le32 token;
+	char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+} __attribute__((packed));
+
+struct snd_soc_tplg_vendor_array {
+	__le32 size;	/* size in bytes of the array, including all elements */
+	__le32 type;	/* SND_SOC_TPLG_TUPLE_TYPE_ */
+	__le32 num_elems;	/* number of elements in array */
+	union {
+		struct snd_soc_tplg_vendor_uuid_elem uuid[0];
+		struct snd_soc_tplg_vendor_value_elem value[0];
+		struct snd_soc_tplg_vendor_string_elem string[0];
+	};
+} __attribute__((packed));
+
 /*
  * Private data.
  * All topology objects may have private data that can be used by the driver or
@@ -130,7 +167,10 @@ struct snd_soc_tplg_hdr {
  */
 struct snd_soc_tplg_private {
 	__le32 size;	/* in bytes of private data */
-	char data[0];
+	union {
+		char data[0];
+		struct snd_soc_tplg_vendor_array array[0];
+	};
 } __attribute__((packed));
 
 /*
-- 
2.5.5

From 9b751b38cbb60bfb08ee796a59d72f40e3cd196d Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:36 +0800
Subject: [PATCH 07/34] topology: Add support for vendor tokens

Vendor can define a token list in SectionVendorTokens. Each token element
is a pair of string ID and integer value. And both the ID and value are
vendor-specific.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/topology.h        |  1 +
 src/topology/data.c       | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 src/topology/elem.c       |  3 +++
 src/topology/parser.c     | 10 ++++++++++
 src/topology/tplg_local.h | 15 ++++++++++++++
 5 files changed, 79 insertions(+)

diff --git a/include/topology.h b/include/topology.h
index 51d282f..0df112c 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -578,6 +578,7 @@ enum snd_tplg_type {
 	SND_TPLG_TYPE_BE,		/*!< BE DAI link */
 	SND_TPLG_TYPE_CC,		/*!< Hostless codec <-> codec link */
 	SND_TPLG_TYPE_MANIFEST,		/*!< Topology manifest */
+	SND_TPLG_TYPE_TOKEN,		/*!< Vendor tokens */
 };
 
 /**
diff --git a/src/topology/data.c b/src/topology/data.c
index 370c0fa..8455c15 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -253,6 +253,56 @@ static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
 	return ret;
 }
 
+/* Parse vendor tokens
+ */
+int tplg_parse_tokens(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, *value;
+	struct tplg_elem *elem;
+	struct tplg_vendor_tokens *tokens;
+	int num_tokens = 0;
+
+	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN);
+	if (!elem)
+		return -ENOMEM;
+
+	snd_config_for_each(i, next, cfg) {
+		num_tokens++;
+	}
+
+	if (!num_tokens)
+		return 0;
+
+	tplg_dbg(" Vendor tokens: %s, %d tokens\n", elem->id, num_tokens);
+
+	tokens = calloc(1, sizeof(*tokens)
+			+ num_tokens * sizeof(struct tplg_token));
+	if (!tokens)
+		return -ENOMEM;
+	elem->tokens = tokens;
+
+	snd_config_for_each(i, next, cfg) {
+
+		n = snd_config_iterator_entry(i);
+		if (snd_config_get_id(n, &id) < 0)
+			continue;
+
+		if (snd_config_get_string(n, &value) < 0)
+			continue;
+
+		elem_copy_text(tokens->token[tokens->num_tokens].id, id,
+				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+		tokens->token[tokens->num_tokens].value = atoi(value);
+		tplg_dbg("\t\t %s : %d\n", tokens->token[tokens->num_tokens].id,
+			tokens->token[tokens->num_tokens].value);
+		tokens->num_tokens++;
+	}
+
+	return 0;
+}
 
 /* Parse Private data.
  *
diff --git a/src/topology/elem.c b/src/topology/elem.c
index f2afaaf..95e3fd4 100644
--- a/src/topology/elem.c
+++ b/src/topology/elem.c
@@ -193,6 +193,9 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
 		list_add_tail(&elem->list, &tplg->cc_list);
 		obj_size = sizeof(struct snd_soc_tplg_link_config);
 		break;
+	case SND_TPLG_TYPE_TOKEN:
+		list_add_tail(&elem->list, &tplg->token_list);
+		break;
 	default:
 		free(elem);
 		return NULL;
diff --git a/src/topology/parser.c b/src/topology/parser.c
index 4546257..264abc8 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -173,6 +173,14 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
 			continue;
 		}
 
+		if (strcmp(id, "SectionVendorTokens") == 0) {
+			err = tplg_parse_compound(tplg, n, tplg_parse_tokens,
+				NULL);
+			if (err < 0)
+				return err;
+			continue;
+		}
+
 		SNDERR("error: unknown section %s\n", id);
 	}
 	return 0;
@@ -407,6 +415,7 @@ snd_tplg_t *snd_tplg_new(void)
 	INIT_LIST_HEAD(&tplg->mixer_list);
 	INIT_LIST_HEAD(&tplg->enum_list);
 	INIT_LIST_HEAD(&tplg->bytes_ext_list);
+	INIT_LIST_HEAD(&tplg->token_list);
 
 	return tplg;
 }
@@ -426,6 +435,7 @@ void snd_tplg_free(snd_tplg_t *tplg)
 	tplg_elem_free_list(&tplg->mixer_list);
 	tplg_elem_free_list(&tplg->enum_list);
 	tplg_elem_free_list(&tplg->bytes_ext_list);
+	tplg_elem_free_list(&tplg->token_list);
 
 	free(tplg);
 }
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 7368a86..679bfff 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -69,6 +69,7 @@ struct snd_tplg {
 	struct list_head route_list;
 	struct list_head text_list;
 	struct list_head pdata_list;
+	struct list_head token_list;
 	struct list_head pcm_config_list;
 	struct list_head pcm_caps_list;
 
@@ -86,6 +87,16 @@ struct tplg_ref {
 	struct list_head list;
 };
 
+/* element for vendor tokens */
+struct tplg_token {
+	char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	unsigned int value;
+};
+
+struct tplg_vendor_tokens {
+	unsigned int num_tokens;
+	struct tplg_token token[0];
+};
 /* topology element */
 struct tplg_elem {
 
@@ -118,6 +129,7 @@ struct tplg_elem {
 		/* these do not map to UAPI structs but are internal only */
 		struct snd_soc_tplg_ctl_tlv *tlv;
 		struct snd_soc_tplg_private *data;
+		struct tplg_vendor_tokens *tokens;
 	};
 
 	/* an element may refer to other elements:
@@ -151,6 +163,9 @@ int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg,
 int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
 	void *private ATTRIBUTE_UNUSED);
 
+int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
+	void *private ATTRIBUTE_UNUSED);
+
 int tplg_parse_control_bytes(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
 
-- 
2.5.5

From fdb9a6d19f8b7cc8252d27e83907d8d1c5e4b53d Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:43 +0800
Subject: [PATCH 08/34] topology: Add support for parsing vendor tuples

Vendor can define several tuple arrays in 'SectionVendorTuples', as
well as the reference to a vendor token list object.

A later patche will copy vendor tuples in ABI format to the private
buffer of its parent data object in the building phase.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/topology.h        |   1 +
 src/topology/data.c       | 240 +++++++++++++++++++++++++++++++++++++++++++++-
 src/topology/elem.c       |   4 +
 src/topology/parser.c     |  10 ++
 src/topology/tplg_local.h |  29 ++++++
 5 files changed, 283 insertions(+), 1 deletion(-)

diff --git a/include/topology.h b/include/topology.h
index 0df112c..b47f422 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -579,6 +579,7 @@ enum snd_tplg_type {
 	SND_TPLG_TYPE_CC,		/*!< Hostless codec <-> codec link */
 	SND_TPLG_TYPE_MANIFEST,		/*!< Topology manifest */
 	SND_TPLG_TYPE_TOKEN,		/*!< Vendor tokens */
+	SND_TPLG_TYPE_TUPLE,		/*!< Vendor tuples */
 };
 
 /**
diff --git a/src/topology/data.c b/src/topology/data.c
index 8455c15..606fcd3 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -253,6 +253,175 @@ static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
 	return ret;
 }
 
+static int parse_tuple_set(snd_tplg_t *tplg, snd_config_t *cfg,
+	struct tplg_tuple_set **s)
+{
+	snd_config_iterator_t i, next;
+	snd_config_t *n;
+	const char *id, *value;
+	struct tplg_tuple_set *set;
+	unsigned int type, num_tuples = 0;
+	struct tplg_tuple *tuple;
+	unsigned long int tuple_val;
+	int len;
+
+	snd_config_get_id(cfg, &id);
+
+	if (strcmp(id, "uuid") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_UUID;
+	else if (strcmp(id, "string") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_STRING;
+	else if (strcmp(id, "bool") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_BOOL;
+	else if (strcmp(id, "byte") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_BYTE;
+	else if (strcmp(id, "short") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_SHORT;
+	else if (strcmp(id, "word") == 0)
+		type = SND_SOC_TPLG_TUPLE_TYPE_WORD;
+	else {
+		SNDERR("error: invalid tuple type '%s'\n", id);
+		return -EINVAL;
+	}
+
+	snd_config_for_each(i, next, cfg)
+		num_tuples++;
+	if (!num_tuples)
+		return 0;
+
+	tplg_dbg("\t %d %s tuples:\n", num_tuples, id);
+	set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple));
+	if (!set)
+		return -ENOMEM;
+
+	set->type = type;
+
+	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;
+
+		tuple = &set->tuple[set->num_tuples];
+		elem_copy_text(tuple->token, id,
+				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+
+		switch (type) {
+		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+			len = strlen(value);
+			if (len > 16 || len == 0) {
+				SNDERR("error: tuple %s: invalid uuid\n", id);
+				goto err;
+			}
+
+			memcpy(tuple->uuid, value, len);
+			tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->uuid);
+			break;
+
+		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+			elem_copy_text(tuple->string, value,
+				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+			tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->string);
+			break;
+
+		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
+			if (strcmp(value, "true") == 0)
+				tuple->value = 1;
+			tplg_dbg("\t\t%s = %d\n", tuple->token, tuple->value);
+			break;
+
+		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
+		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
+		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
+			errno = 0;
+			/* no support for negative value */
+			tuple_val = strtoul(value, NULL, 0);
+			if ((errno == ERANGE && tuple_val == ULONG_MAX)
+				|| (errno != 0 && tuple_val == 0)) {
+				SNDERR("error: tuple %s:strtoul fail\n", id);
+				goto err;
+			}
+
+			if ((type == SND_SOC_TPLG_TUPLE_TYPE_WORD
+					&& tuple_val > UINT_MAX)
+				|| (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT
+					&& tuple_val > USHRT_MAX)
+				|| (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE
+					&& tuple_val > UCHAR_MAX)) {
+				SNDERR("error: tuple %s: invalid value\n", id);
+				goto err;
+			}
+
+			tuple->value = (unsigned int) tuple_val;
+			tplg_dbg("\t\t%s = 0x%x\n", tuple->token, tuple->value);
+			break;
+
+		default:
+			break;
+		}
+
+		set->num_tuples++;
+	}
+
+	*s = set;
+	return 0;
+
+err:
+	free(set);
+	return -EINVAL;
+}
+
+static int parse_tuple_sets(snd_tplg_t *tplg, snd_config_t *cfg,
+	struct tplg_vendor_tuples *tuples)
+{
+	snd_config_iterator_t i, next;
+	snd_config_t *n;
+	const char *id;
+	unsigned int num_tuple_sets = 0;
+	int err;
+
+	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+		SNDERR("error: compound type expected for %s", id);
+		return -EINVAL;
+	}
+
+	snd_config_for_each(i, next, cfg) {
+		num_tuple_sets++;
+	}
+
+	if (!num_tuple_sets)
+		return 0;
+
+	tuples->set = calloc(1, num_tuple_sets * sizeof(void *));
+	if (!tuples->set)
+		return -ENOMEM;
+
+	snd_config_for_each(i, next, cfg) {
+		n = snd_config_iterator_entry(i);
+		if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
+			SNDERR("error: compound type expected for %s, is %d",
+			id, snd_config_get_type(n));
+			return -EINVAL;
+		}
+
+		err = parse_tuple_set(tplg, n, &tuples->set[tuples->num_sets]);
+		if (err < 0)
+			return err;
+
+		/* overlook empty tuple sets */
+		if (tuples->set[tuples->num_sets])
+			tuples->num_sets++;
+	}
+
+	return 0;
+}
+
 /* Parse vendor tokens
  */
 int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
@@ -304,10 +473,71 @@ int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
 	return 0;
 }
 
+/* Parse vendor tuples.
+ */
+int tplg_parse_tuples(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, *value;
+	struct tplg_elem *elem;
+	struct tplg_vendor_tuples *tuples;
+	int err;
+
+	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE);
+	if (!elem)
+		return -ENOMEM;
+
+	tplg_dbg(" Vendor Tuples: %s\n", elem->id);
+
+	tuples = calloc(1, sizeof(*tuples));
+	if (!tuples)
+		return -ENOMEM;
+	elem->tuples = tuples;
+
+	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, "tokens") == 0) {
+			if (snd_config_get_string(n, &value) < 0)
+				return -EINVAL;
+			tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value);
+			tplg_dbg("\t refer to vendor tokens: %s\n", value);
+		}
+
+		if (strcmp(id, "tuples") == 0) {
+			err = parse_tuple_sets(tplg, n, tuples);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+/* Free handler of tuples */
+void tplg_free_tuples(void *obj)
+{
+	struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj;
+	int i;
+
+	if (!tuples || !tuples->set)
+		return;
+
+	for (i = 0; i < tuples->num_sets; i++)
+		free(tuples->set[i]);
+
+	free(tuples->set);
+}
+
 /* Parse Private data.
  *
  * Object private data can either be from file or defined as bytes, shorts,
- * words.
+ * words, tuples.
  */
 int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
 	void *private ATTRIBUTE_UNUSED)
@@ -365,6 +595,14 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
 			continue;
 		}
 
+		if (strcmp(id, "tuples") == 0) {
+			if (snd_config_get_string(n, &val) < 0)
+				return -EINVAL;
+			tplg_dbg(" Data: %s\n", val);
+			tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val);
+			continue;
+		}
+
 		if (strcmp(id, "index") == 0) {
 			if (snd_config_get_string(n, &val) < 0)
 				return -EINVAL;
diff --git a/src/topology/elem.c b/src/topology/elem.c
index 95e3fd4..50414f0 100644
--- a/src/topology/elem.c
+++ b/src/topology/elem.c
@@ -196,6 +196,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
 	case SND_TPLG_TYPE_TOKEN:
 		list_add_tail(&elem->list, &tplg->token_list);
 		break;
+	case SND_TPLG_TYPE_TUPLE:
+		list_add_tail(&elem->list, &tplg->tuple_list);
+		elem->free = tplg_free_tuples;
+		break;
 	default:
 		free(elem);
 		return NULL;
diff --git a/src/topology/parser.c b/src/topology/parser.c
index 264abc8..0d967b4 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -181,6 +181,14 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
 			continue;
 		}
 
+		if (strcmp(id, "SectionVendorTuples") == 0) {
+			err = tplg_parse_compound(tplg, n, tplg_parse_tuples,
+				NULL);
+			if (err < 0)
+				return err;
+			continue;
+		}
+
 		SNDERR("error: unknown section %s\n", id);
 	}
 	return 0;
@@ -416,6 +424,7 @@ snd_tplg_t *snd_tplg_new(void)
 	INIT_LIST_HEAD(&tplg->enum_list);
 	INIT_LIST_HEAD(&tplg->bytes_ext_list);
 	INIT_LIST_HEAD(&tplg->token_list);
+	INIT_LIST_HEAD(&tplg->tuple_list);
 
 	return tplg;
 }
@@ -436,6 +445,7 @@ void snd_tplg_free(snd_tplg_t *tplg)
 	tplg_elem_free_list(&tplg->enum_list);
 	tplg_elem_free_list(&tplg->bytes_ext_list);
 	tplg_elem_free_list(&tplg->token_list);
+	tplg_elem_free_list(&tplg->tuple_list);
 
 	free(tplg);
 }
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 679bfff..4d59a1f 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -70,6 +70,7 @@ struct snd_tplg {
 	struct list_head text_list;
 	struct list_head pdata_list;
 	struct list_head token_list;
+	struct list_head tuple_list;
 	struct list_head pcm_config_list;
 	struct list_head pcm_caps_list;
 
@@ -97,6 +98,28 @@ struct tplg_vendor_tokens {
 	unsigned int num_tokens;
 	struct tplg_token token[0];
 };
+
+/* element for vendor tuples */
+struct tplg_tuple {
+	char token[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	union {
+		char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+		char uuid[16];
+		unsigned int value;
+	};
+};
+
+struct tplg_tuple_set {
+	unsigned int  type; /* uuid, bool, byte, short, word, string*/
+	unsigned int  num_tuples;
+	struct tplg_tuple tuple[0];
+};
+
+struct tplg_vendor_tuples {
+	unsigned int  num_sets;
+	struct tplg_tuple_set **set;
+};
+
 /* topology element */
 struct tplg_elem {
 
@@ -130,6 +153,7 @@ struct tplg_elem {
 		struct snd_soc_tplg_ctl_tlv *tlv;
 		struct snd_soc_tplg_private *data;
 		struct tplg_vendor_tokens *tokens;
+		struct tplg_vendor_tuples *tuples;
 	};
 
 	/* an element may refer to other elements:
@@ -166,6 +190,11 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
 int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
 	void *private ATTRIBUTE_UNUSED);
 
+int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
+	void *private ATTRIBUTE_UNUSED);
+
+void tplg_free_tuples(void *obj);
+
 int tplg_parse_control_bytes(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
 
-- 
2.5.5

From 0c5e5c1801e5b1b55e46144ee29ca7a71f2812b0 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Thu, 7 Apr 2016 15:29:49 +0800
Subject: [PATCH 09/34] topology: Build data objects with tuples

For data objects with tuples, the parser will bind the vendor tuples
and tokens, copy the tuples to the private buffer of its parent data
object. Then later the builder will export the vendor tuples as private
binary data for the control or widgets objects.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/data.c       | 213 ++++++++++++++++++++++++++++++++++++++++++++++
 src/topology/parser.c     |   4 +
 src/topology/tplg_local.h |   1 +
 3 files changed, 218 insertions(+)

diff --git a/src/topology/data.c b/src/topology/data.c
index 606fcd3..19c31bf 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -253,6 +253,198 @@ static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
 	return ret;
 }
 
+/* get the token integer value from its id */
+static int get_token_value(const char *token_id,
+	struct tplg_vendor_tokens *tokens)
+{
+	int i;
+
+	for (i = 0; i < tokens->num_tokens; i++) {
+		if (strcmp(token_id, tokens->token[i].id) == 0)
+			return tokens->token[i].value;
+	}
+
+	SNDERR("error: cannot find token id '%s'\n", token_id);
+	return -1;
+}
+
+/* get the vendor tokens referred by the vendor tuples */
+static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem)
+{
+	struct tplg_ref *ref;
+	struct list_head *base, *pos;
+	int err = 0;
+
+	base = &elem->ref_list;
+	list_for_each(pos, base) {
+
+		ref = list_entry(pos, struct tplg_ref, list);
+
+		if (!ref->id || ref->type != SND_TPLG_TYPE_TOKEN)
+			continue;
+
+		if (!ref->elem) {
+			ref->elem = tplg_elem_lookup(&tplg->token_list,
+						ref->id, SND_TPLG_TYPE_TOKEN);
+		}
+
+		return ref->elem;
+	}
+
+	return NULL;
+}
+
+/* check if a data element has tuples */
+static bool has_tuples(struct tplg_elem *elem)
+{
+	struct tplg_ref *ref;
+	struct list_head *base, *pos;
+	int err = 0;
+
+	base = &elem->ref_list;
+	list_for_each(pos, base) {
+
+		ref = list_entry(pos, struct tplg_ref, list);
+		if (ref->id && ref->type == SND_TPLG_TYPE_TUPLE)
+			return true;
+	}
+
+	return false;
+}
+
+/* get size of a tuple element from its type */
+static unsigned int get_tuple_size(int type)
+{
+	switch (type) {
+
+	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+		return sizeof(struct snd_soc_tplg_vendor_uuid_elem);
+
+	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+		return sizeof(struct snd_soc_tplg_vendor_string_elem);
+
+	default:
+		return sizeof(struct snd_soc_tplg_vendor_value_elem);
+	}
+}
+
+/* fill a data element's private buffer with its tuples */
+static int copy_tuples(struct tplg_elem *elem,
+	struct tplg_vendor_tuples *tuples, struct tplg_vendor_tokens *tokens)
+{
+	struct snd_soc_tplg_private *priv = elem->data;
+	struct tplg_tuple_set *tuple_set;
+	struct tplg_tuple *tuple;
+	struct snd_soc_tplg_vendor_array *array;
+	struct snd_soc_tplg_vendor_uuid_elem *uuid;
+	struct snd_soc_tplg_vendor_string_elem *string;
+	struct snd_soc_tplg_vendor_value_elem *value;
+	int set_size, size, off;
+	int i, j, token_val;
+
+	if (priv) {
+		SNDERR("error: %s has more data than tuples\n", elem->id);
+		return -EINVAL;
+	}
+
+	size = 0;
+	for (i = 0; i < tuples->num_sets ; i++) {
+		tuple_set = tuples->set[i];
+		set_size = sizeof(struct snd_soc_tplg_vendor_array)
+			+ get_tuple_size(tuple_set->type)
+			* tuple_set->num_tuples;
+		size += set_size;
+		if (size > TPLG_MAX_PRIV_SIZE) {
+			SNDERR("error: data too big %d\n", size);
+			return -EINVAL;
+		}
+
+		if (priv != NULL)
+			priv = realloc(priv, sizeof(*priv) + size);
+		else
+			priv = calloc(1, sizeof(*priv) + size);
+		if (!priv)
+			return -ENOMEM;
+
+		off = priv->size;
+		priv->size = size;
+
+		array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
+		array->size = set_size;
+		array->type = tuple_set->type;
+		array->num_elems = tuple_set->num_tuples;
+
+		/* fill the private data buffer */
+		for (j = 0; j < tuple_set->num_tuples; j++) {
+			tuple = &tuple_set->tuple[j];
+			token_val = get_token_value(tuple->token, tokens);
+			if (token_val  < 0)
+				return -EINVAL;
+
+			switch (tuple_set->type) {
+			case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+				uuid = &array->uuid[j];
+				uuid->token = token_val;
+				memcpy(uuid->uuid, tuple->uuid, 16);
+				break;
+
+			case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+				string = &array->string[j];
+				string->token = token_val;
+				elem_copy_text(string->string, tuple->string,
+					SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+				break;
+
+			default:
+				value = &array->value[j];
+				value->token = token_val;
+				value->value = tuple->value;
+				break;
+			}
+		}
+	}
+
+	elem->data = priv;
+	return 0;
+}
+
+/* build a data element from its tuples */
+static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem)
+{
+	struct tplg_ref *ref;
+	struct list_head *base, *pos;
+	struct tplg_elem *tuples, *tokens;
+
+	base = &elem->ref_list;
+	list_for_each(pos, base) {
+
+		ref = list_entry(pos, struct tplg_ref, list);
+
+		if (!ref->id || ref->type != SND_TPLG_TYPE_TUPLE)
+			continue;
+
+		tplg_dbg("look up tuples %s\n", ref->id);
+
+		if (!ref->elem)
+			ref->elem = tplg_elem_lookup(&tplg->tuple_list,
+						ref->id, SND_TPLG_TYPE_TUPLE);
+		tuples = ref->elem;
+		if (!tuples)
+			return -EINVAL;
+
+		tplg_dbg("found tuples %s\n", tuples->id);
+		tokens = get_tokens(tplg, tuples);
+		if (!tokens)
+			return -EINVAL;
+
+		tplg_dbg("found tokens %s\n", tokens->id);
+		/* a data object can only have one tuples object */
+		return copy_tuples(elem, tuples->tuples, tokens->tokens);
+	}
+
+	return 0;
+}
+
 static int parse_tuple_set(snd_tplg_t *tplg, snd_config_t *cfg,
 	struct tplg_tuple_set **s)
 {
@@ -683,3 +875,24 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
 	memcpy(priv->data, ref->data->data, priv_data_size);
 	return 0;
 }
+
+/* check data objects and build those with tuples */
+int tplg_build_data(snd_tplg_t *tplg)
+{
+	struct list_head *base, *pos;
+	struct tplg_elem *elem;
+	int err = 0;
+
+	base = &tplg->pdata_list;
+	list_for_each(pos, base) {
+
+		elem = list_entry(pos, struct tplg_elem, list);
+		if (has_tuples(elem)) {
+			err = build_tuples(tplg, elem);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
diff --git a/src/topology/parser.c b/src/topology/parser.c
index 0d967b4..30d91f9 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -242,6 +242,10 @@ static int tplg_build_integ(snd_tplg_t *tplg)
 {
 	int err;
 
+	err = tplg_build_data(tplg);
+	if (err <  0)
+		return err;
+
 	err = tplg_build_controls(tplg);
 	if (err <  0)
 		return err;
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 4d59a1f..4c601d4 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -222,6 +222,7 @@ int tplg_parse_be(snd_tplg_t *tplg,
 int tplg_parse_cc(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
 
+int tplg_build_data(snd_tplg_t *tplg);
 int tplg_build_controls(snd_tplg_t *tplg);
 int tplg_build_widgets(snd_tplg_t *tplg);
 int tplg_build_routes(snd_tplg_t *tplg);
-- 
2.5.5

From e57b521c61f0df14b660ce6ba8c5009a63f5b115 Mon Sep 17 00:00:00 2001
From: Hsin-Yu Chao <hychao@chromium.org>
Date: Wed, 13 Apr 2016 18:53:09 +0800
Subject: [PATCH 10/34] ucm: add cset-tlv

This patch enables UCM to set a file in TLV format to kcontrol by:
cset-tlv "name='<kcontrol-name>' <path-to-file>"
This new 'cset-tlv' command will be used to write audio DSP to
specific alsa control, where the driver expectes a file in TLV
format.
The TLV file to set to kcontrol will be checked first by file size
not larger than 16 MB, and then examine if the length field reports
correct number of bytes in the TLV file.

Signed-off-by: Hsin-Yu Chao <hychao@chromium.org>
Reviewed-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/ucm/main.c      | 94 +++++++++++++++++++++++++++++++++++++++++++++--------
 src/ucm/parser.c    | 10 ++++++
 src/ucm/ucm_local.h |  1 +
 3 files changed, 92 insertions(+), 13 deletions(-)

diff --git a/src/ucm/main.c b/src/ucm/main.c
index 7e44603..24d9510 100644
--- a/src/ucm/main.c
+++ b/src/ucm/main.c
@@ -161,6 +161,57 @@ static int open_ctl(snd_use_case_mgr_t *uc_mgr,
 	return 0;
 }
 
+static int read_tlv_file(unsigned int **res,
+			 const char *filepath)
+{
+	int err = 0;
+	int fd;
+	struct stat st;
+	size_t sz;
+	ssize_t sz_read;
+	struct snd_ctl_tlv *tlv;
+
+	fd = open(filepath, O_RDONLY);
+	if (fd < 0) {
+		err = -errno;
+		return err;
+	}
+	if (fstat(fd, &st) == -1) {
+		err = -errno;
+		goto __fail;
+	}
+	sz = st.st_size;
+	if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) {
+		uc_error("File size should be less than 16 MB "
+			 "and multiple of 4");
+		err = -EINVAL;
+		goto __fail;
+	}
+	*res = malloc(sz);
+	if (res == NULL) {
+		err = -ENOMEM;
+		goto __fail;
+	}
+	sz_read = read(fd, *res, sz);
+	if (sz_read < 0 || (size_t)sz_read != sz) {
+		err = -EIO;
+		free(*res);
+		*res = NULL;
+	}
+	/* Check if the tlv file specifies valid size. */
+	tlv = (struct snd_ctl_tlv *)(*res);
+	if (tlv->length + 2 * sizeof(unsigned int) != sz) {
+		uc_error("Invalid tlv size: %d", tlv->length);
+		err = -EINVAL;
+		free(*res);
+		*res = NULL;
+	}
+
+__fail:
+	close(fd);
+	return err;
+}
+
 static int binary_file_parse(snd_ctl_elem_value_t *dst,
 			      snd_ctl_elem_info_t *info,
 			      const char *filepath)
@@ -226,6 +277,7 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
 	snd_ctl_elem_id_t *id;
 	snd_ctl_elem_value_t *value;
 	snd_ctl_elem_info_t *info;
+	unsigned int *res = NULL;
 
 	snd_ctl_elem_id_malloc(&id);
 	snd_ctl_elem_value_malloc(&value);
@@ -241,23 +293,36 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
 		err = -EINVAL;
 		goto __fail;
 	}
-	snd_ctl_elem_value_set_id(value, id);
 	snd_ctl_elem_info_set_id(info, id);
-	err = snd_ctl_elem_read(ctl, value);
-	if (err < 0)
-		goto __fail;
 	err = snd_ctl_elem_info(ctl, info);
 	if (err < 0)
 		goto __fail;
-	if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
-		err = binary_file_parse(value, info, pos);
-	else
-		err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
-	if (err < 0)
-		goto __fail;
-	err = snd_ctl_elem_write(ctl, value);
-	if (err < 0)
-		goto __fail;
+	if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) {
+		if (!snd_ctl_elem_info_is_tlv_writable(info)) {
+			err = -EINVAL;
+			goto __fail;
+		}
+		err = read_tlv_file(&res, pos);
+		if (err < 0)
+			goto __fail;
+		err = snd_ctl_elem_tlv_write(ctl, id, res);
+		if (err < 0)
+			goto __fail;
+	} else {
+		snd_ctl_elem_value_set_id(value, id);
+		err = snd_ctl_elem_read(ctl, value);
+		if (err < 0)
+			goto __fail;
+		if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
+			err = binary_file_parse(value, info, pos);
+		else
+			err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
+		if (err < 0)
+			goto __fail;
+		err = snd_ctl_elem_write(ctl, value);
+		if (err < 0)
+			goto __fail;
+	}
 	err = 0;
       __fail:
 	if (id != NULL)
@@ -266,6 +331,8 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
 		free(value);
 	if (info != NULL)
 		free(info);
+	if (res != NULL)
+		free(res);
 
 	return err;
 }
@@ -298,6 +365,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
 			break;
 		case SEQUENCE_ELEMENT_TYPE_CSET:
 		case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
+		case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
 			if (cdev == NULL) {
 				char *playback_ctl = NULL;
 				char *capture_ctl = NULL;
diff --git a/src/ucm/parser.c b/src/ucm/parser.c
index 8405bd2..13f62d7 100644
--- a/src/ucm/parser.c
+++ b/src/ucm/parser.c
@@ -316,6 +316,16 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
 			continue;
 		}
 
+		if (strcmp(cmd, "cset-tlv") == 0) {
+			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
+			err = parse_string(n, &curr->data.cset);
+			if (err < 0) {
+				uc_error("error: cset-tlv requires a string!");
+				return err;
+			}
+			continue;
+		}
+
 		if (strcmp(cmd, "usleep") == 0) {
 			curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
 			err = snd_config_get_integer(n, &curr->data.sleep);
diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
index 3a5d2c2..b89de2a 100644
--- a/src/ucm/ucm_local.h
+++ b/src/ucm/ucm_local.h
@@ -48,6 +48,7 @@
 #define SEQUENCE_ELEMENT_TYPE_SLEEP	3
 #define SEQUENCE_ELEMENT_TYPE_EXEC	4
 #define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE	5
+#define SEQUENCE_ELEMENT_TYPE_CSET_TLV	6
 
 struct ucm_value {
         struct list_head list;
-- 
2.5.5

From fdba9e1bad8f769a6137e565471f0227f23a3132 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 14 Apr 2016 17:33:03 +0200
Subject: [PATCH 11/34] pcm: Fallback open as the first instance for dmix & co

dmix and other PCM plugins tries to open a secondary stream with
O_APPEND flag when the shmem was already attached by another.
However, when another streams have been already closed after the
shmem check, this open may return the error EBADFD, since the kernel
accepts O_APPEND only for the secondary streams.

This patch adds a workaround for such a case.  It just retries opening
the stream as the first instance (i.e. without O_APPEND flag).
This is basically safe behavior (the kernel takes care of races), even
we may do this even unconditionally.  But it's bad from the
performance POV, so we do it only when really needed.

Reported-by: Lars Lindqvist <lars.lindqvist@yandex.ru>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_dmix.c   | 8 ++++++++
 src/pcm/pcm_dshare.c | 8 ++++++++
 src/pcm/pcm_dsnoop.c | 8 ++++++++
 3 files changed, 24 insertions(+)

diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index b26a5c7..007d356 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -1020,6 +1020,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 	dmix->max_periods = opts->max_periods;
 	dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
 
+ retry:
 	if (first_instance) {
 		/* recursion is already checked in
 		   snd_pcm_direct_get_slave_ipc_offset() */
@@ -1076,6 +1077,13 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 						 SND_PCM_APPEND,
 						 NULL);
 			if (ret < 0) {
+				/* all other streams have been closed;
+				 * retry as the first instance
+				 */
+				if (ret == -EBADFD) {
+					first_instance = 1;
+					goto retry;
+				}
 				SNDERR("unable to open slave");
 				goto _err;
 			}
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index 58e47bb..adb3587 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -690,6 +690,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 		break;
 	}
 
+ retry:
 	first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare);
 	if (ret < 0) {
 		SNDERR("unable to create IPC shm instance");
@@ -758,6 +759,13 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 						 SND_PCM_APPEND,
 						 NULL);
 			if (ret < 0) {
+				/* all other streams have been closed;
+				 * retry as the first instance
+				 */
+				if (ret == -EBADFD) {
+					first_instance = 1;
+					goto retry;
+				}
 				SNDERR("unable to open slave");
 				goto _err;
 			}
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index 576c35b..8ff0ba5 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -583,6 +583,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 		break;
 	}
 		
+ retry:
 	first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
 	if (ret < 0) {
 		SNDERR("unable to create IPC shm instance");
@@ -651,6 +652,13 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 						 SND_PCM_APPEND,
 						 NULL);
 			if (ret < 0) {
+				/* all other streams have been closed;
+				 * retry as the first instance
+				 */
+				if (ret == -EBADFD) {
+					first_instance = 1;
+					goto retry;
+				}
 				SNDERR("unable to open slave");
 				goto _err;
 			}
-- 
2.5.5

From f5c313eae5c26d6843a4f860743151f53b2f4041 Mon Sep 17 00:00:00 2001
From: Shreyas NC <shreyas.nc@intel.com>
Date: Thu, 28 Apr 2016 11:07:56 +0530
Subject: [PATCH 12/34] conf: topology: Add Skylake i2s conf

The Skylake topology configuration for simple topology graph is
provided. This exposes the PCM capabilities of the DSP.

Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 configure.ac                                       |   1 +
 src/conf/topology/Makefile.am                      |   2 +-
 src/conf/topology/sklrt286/Makefile.am             |   4 +
 src/conf/topology/sklrt286/codec0_in-cpr-1.bin     | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/codec0_in-mi.bin        | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/codec0_out-cpr-4.bin    | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/codec0_out-mo.bin       | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/codec1_out-cpr-5.bin    | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/codec1_out-mo.bin       | Bin 0 -> 4244 bytes
 .../topology/sklrt286/dmic01_hifi_in-cpr-3.bin     | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/dmic01_hifi_in-mi.bin   | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi1_pt_out-cpr-7.bin  | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi1_pt_out-cpr-8.bin  | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi2_pt_out-cpr-10.bin | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi2_pt_out-cpr-9.bin  | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi3_pt_out-cpr-11.bin | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/hdmi3_pt_out-cpr-12.bin | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/media0_in-cpr-0.bin     | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/media0_in-mi.bin        | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/media0_out-cpr-6.bin    | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/media0_out-mo.bin       | Bin 0 -> 4244 bytes
 src/conf/topology/sklrt286/skl_i2s.conf            | 342 +++++++++++++++++++++
 22 files changed, 348 insertions(+), 1 deletion(-)
 create mode 100644 src/conf/topology/sklrt286/Makefile.am
 create mode 100644 src/conf/topology/sklrt286/codec0_in-cpr-1.bin
 create mode 100644 src/conf/topology/sklrt286/codec0_in-mi.bin
 create mode 100644 src/conf/topology/sklrt286/codec0_out-cpr-4.bin
 create mode 100644 src/conf/topology/sklrt286/codec0_out-mo.bin
 create mode 100644 src/conf/topology/sklrt286/codec1_out-cpr-5.bin
 create mode 100644 src/conf/topology/sklrt286/codec1_out-mo.bin
 create mode 100644 src/conf/topology/sklrt286/dmic01_hifi_in-cpr-3.bin
 create mode 100644 src/conf/topology/sklrt286/dmic01_hifi_in-mi.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi1_pt_out-cpr-7.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi1_pt_out-cpr-8.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi2_pt_out-cpr-10.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi2_pt_out-cpr-9.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi3_pt_out-cpr-11.bin
 create mode 100644 src/conf/topology/sklrt286/hdmi3_pt_out-cpr-12.bin
 create mode 100644 src/conf/topology/sklrt286/media0_in-cpr-0.bin
 create mode 100644 src/conf/topology/sklrt286/media0_in-mi.bin
 create mode 100644 src/conf/topology/sklrt286/media0_out-cpr-6.bin
 create mode 100644 src/conf/topology/sklrt286/media0_out-mo.bin
 create mode 100644 src/conf/topology/sklrt286/skl_i2s.conf

diff --git a/configure.ac b/configure.ac
index c265ec9..1bf75e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -661,6 +661,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/conf/topology/Makefile \
 	  src/conf/topology/broadwell/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
+	  src/conf/topology/sklrt286/Makefile \
 	  alsalisp/Makefile aserver/Makefile \
 	  test/Makefile test/lsb/Makefile \
 	  utils/Makefile utils/alsa-lib.spec utils/alsa.pc)
diff --git a/src/conf/topology/Makefile.am b/src/conf/topology/Makefile.am
index f56a96c..cbdb7cf 100644
--- a/src/conf/topology/Makefile.am
+++ b/src/conf/topology/Makefile.am
@@ -1 +1 @@
-SUBDIRS=broadwell
+SUBDIRS=broadwell sklrt286
diff --git a/src/conf/topology/sklrt286/Makefile.am b/src/conf/topology/sklrt286/Makefile.am
new file mode 100644
index 0000000..facc508
--- /dev/null
+++ b/src/conf/topology/sklrt286/Makefile.am
@@ -0,0 +1,4 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+sklrt286dir = $(alsaconfigdir)/topology/sklrt286
+sklrt286_DATA = skl_i2s.conf media0_in-cpr-0.bin media0_in-mi.bin media0_out-mo.bin media0_out-cpr-6.bin codec0_out-mo.bin codec0_out-cpr-4.bin codec1_out-mo.bin codec1_out-cpr-5.bin codec0_in-cpr-1.bin codec0_in-mi.bin dmic01_hifi_in-cpr-3.bin dmic01_hifi_in-mi.bin hdmi1_pt_out-cpr-7.bin hdmi1_pt_out-cpr-8.bin hdmi2_pt_out-cpr-9.bin hdmi2_pt_out-cpr-10.bin hdmi3_pt_out-cpr-11.bin hdmi3_pt_out-cpr-12.bin 
+EXTRA_DIST = $(sklrt286_DATA)
diff --git a/src/conf/topology/sklrt286/skl_i2s.conf b/src/conf/topology/sklrt286/skl_i2s.conf
new file mode 100644
index 0000000..6da224f
--- /dev/null
+++ b/src/conf/topology/sklrt286/skl_i2s.conf
@@ -0,0 +1,342 @@
+SectionData."media0_in cpr 0" {
+	file "sklrt286/media0_in-cpr-0.bin"
+}
+SectionData."media0_in mi" {
+	file "sklrt286/media0_in-mi.bin"
+}
+SectionData."media0_out mo" {
+	file "sklrt286/media0_out-mo.bin"
+}
+SectionData."media0_out cpr 6" {
+	file "sklrt286/media0_out-cpr-6.bin"
+}
+SectionData."codec0_out mo" {
+	file "sklrt286/codec0_out-mo.bin"
+}
+SectionData."codec0_out cpr 4" {
+	file "sklrt286/codec0_out-cpr-4.bin"
+}
+SectionData."codec1_out mo" {
+	file "sklrt286/codec1_out-mo.bin"
+}
+SectionData."codec1_out cpr 5" {
+	file "sklrt286/codec1_out-cpr-5.bin"
+}
+SectionData."codec0_in cpr 1" {
+	file "sklrt286/codec0_in-cpr-1.bin"
+}
+SectionData."codec0_in mi" {
+	file "sklrt286/codec0_in-mi.bin"
+}
+SectionData."dmic01_hifi_in cpr 3" {
+	file "sklrt286/dmic01_hifi_in-cpr-3.bin"
+}
+SectionData."dmic01_hifi_in mi" {
+	file "sklrt286/dmic01_hifi_in-mi.bin"
+}
+SectionData."hdmi1_pt_out cpr 7" {
+	file "sklrt286/hdmi1_pt_out-cpr-7.bin"
+}
+SectionData."hdmi1_pt_out cpr 8" {
+	file "sklrt286/hdmi1_pt_out-cpr-8.bin"
+}
+SectionData."hdmi2_pt_out cpr 9" {
+	file "sklrt286/hdmi2_pt_out-cpr-9.bin"
+}
+SectionData."hdmi2_pt_out cpr 10" {
+	file "sklrt286/hdmi2_pt_out-cpr-10.bin"
+}
+SectionData."hdmi3_pt_out cpr 11" {
+	file "sklrt286/hdmi3_pt_out-cpr-11.bin"
+}
+SectionData."hdmi3_pt_out cpr 12" {
+	file "sklrt286/hdmi3_pt_out-cpr-12.bin"
+}
+
+SectionControlMixer."media0_in mi Switch" {
+	index"1"
+	invert "false"
+	max "1"
+	min"0"
+	no_pm "true"
+	channel."fl" {
+		reg "-1"
+		shift "0"
+	}
+	channel."fr" {
+		reg "-1"
+		shift "0"
+	}
+	ops."ctl" {
+		get "64"
+		put "64"
+		info "64"
+	}
+}
+SectionControlMixer."codec0_in mi Switch" {
+	index"1"
+	invert "false"
+	max "1"
+	min"0"
+	no_pm "true"
+	channel."fl" {
+		reg "-1"
+		shift "0"
+	}
+	channel."fr" {
+		reg "-1"
+		shift "0"
+	}
+	ops."ctl" {
+		get "64"
+		put "64"
+		info "64"
+	}
+}
+SectionControlMixer."dmic01_hifi_in mi Switch" {
+	index"1"
+	invert "false"
+	max "1"
+	min"0"
+	no_pm "true"
+	channel."fl" {
+		reg "-1"
+		shift "0"
+	}
+	channel."fr" {
+		reg "-1"
+		shift "0"
+	}
+	ops."ctl" {
+		get "64"
+		put "64"
+		info "64"
+	}
+}
+
+
+SectionWidget."media0_in cpr 0" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "media0_in cpr 0"
+}
+SectionWidget."media0_in mi" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	event_flags "9"
+	subseq "10"
+	data "media0_in mi"
+}
+SectionWidget."media0_out mo" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "1"
+	event_flags "15"
+	subseq "10"
+	data "media0_out mo"
+	mixer [
+		"media0_in mi Switch"
+		"codec0_in mi Switch"
+		"dmic01_hifi_in mi Switch"
+	]
+}
+SectionWidget."media0_out cpr 6" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "media0_out cpr 6"
+}
+SectionWidget."codec0_out mo" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "1"
+	event_flags "15"
+	subseq "10"
+	data "codec0_out mo"
+	mixer [
+		"media0_in mi Switch"
+		"codec0_in mi Switch"
+		"dmic01_hifi_in mi Switch"
+	]
+}
+SectionWidget."codec0_out cpr 4" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "codec0_out cpr 4"
+}
+SectionWidget."codec0_out" {
+	index"1"
+	type"aif_out"
+	no_pm "true"
+}
+SectionWidget."codec1_out mo" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "1"
+	event_flags "15"
+	subseq "10"
+	data "codec1_out mo"
+	mixer [
+		"media0_in mi Switch"
+		"codec0_in mi Switch"
+		"dmic01_hifi_in mi Switch"
+	]
+}
+SectionWidget."codec1_out cpr 5" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "codec1_out cpr 5"
+}
+SectionWidget."codec1_out" {
+	index"1"
+	type"aif_out"
+	no_pm "true"
+}
+SectionWidget."codec0_in cpr 1" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "codec0_in cpr 1"
+}
+SectionWidget."codec0_in mi" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	event_flags "9"
+	subseq "10"
+	data "codec0_in mi"
+}
+SectionWidget."codec0_in" {
+	index"1"
+	type"aif_in"
+	no_pm "true"
+}
+SectionWidget."dmic01_hifi_in cpr 3" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "dmic01_hifi_in cpr 3"
+}
+SectionWidget."dmic01_hifi_in mi" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	event_flags "9"
+	subseq "10"
+	data "dmic01_hifi_in mi"
+}
+SectionWidget."dmic01_hifi" {
+	index"1"
+	type"aif_in"
+	no_pm "true"
+}
+SectionWidget."hdmi1_pt_out cpr 7" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "hdmi1_pt_out cpr 7"
+}
+SectionWidget."hdmi1_pt_out cpr 8" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "hdmi1_pt_out cpr 8"
+}
+SectionWidget."iDisp1_out" {
+	index"1"
+	type"aif_out"
+	no_pm "true"
+}
+SectionWidget."hdmi2_pt_out cpr 9" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "hdmi2_pt_out cpr 9"
+}
+SectionWidget."hdmi2_pt_out cpr 10" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "hdmi2_pt_out cpr 10"
+}
+SectionWidget."iDisp2_out" {
+	index"1"
+	type"aif_out"
+	no_pm "true"
+}
+SectionWidget."hdmi3_pt_out cpr 11" {
+	index"1"
+	type"mixer"
+	no_pm "true"
+	event_type "3"
+	event_flags "9"
+	data "hdmi3_pt_out cpr 11"
+}
+SectionWidget."hdmi3_pt_out cpr 12" {
+	index"1"
+	type"pga"
+	no_pm "true"
+	event_type "4"
+	data "hdmi3_pt_out cpr 12"
+}
+SectionGraph."Pipeline 1 Graph" {
+	index"1"
+	lines [
+		"media0_in mi, , media0_in cpr 0"
+		"media0_in cpr 0, , System Playback"
+		"media0_out mo, media0_in mi Switch, media0_in mi"
+		"media0_out mo, codec0_in mi Switch, codec0_in mi"
+		"media0_out mo, dmic01_hifi_in mi Switch, dmic01_hifi_in mi"
+		"media0_out cpr 6, , media0_out mo"
+		"System Capture, , media0_out cpr 6"
+		"codec0_out mo, media0_in mi Switch, media0_in mi"
+		"codec0_out mo, codec0_in mi Switch, codec0_in mi"
+		"codec0_out mo, dmic01_hifi_in mi Switch, dmic01_hifi_in mi"
+		"codec0_out cpr 4, , codec0_out mo"
+		"codec0_out, , codec0_out cpr 4"
+		"codec1_out mo, media0_in mi Switch, media0_in mi"
+		"codec1_out mo, codec0_in mi Switch, codec0_in mi"
+		"codec1_out mo, dmic01_hifi_in mi Switch, dmic01_hifi_in mi"
+		"codec1_out cpr 5, , codec1_out mo"
+		"codec1_out, , codec1_out cpr 5"
+		"codec0_in mi, , codec0_in cpr 1"
+		"codec0_in cpr 1, , codec0_in"
+		"dmic01_hifi_in mi, , dmic01_hifi_in cpr 3"
+		"dmic01_hifi_in cpr 3, , dmic01_hifi"
+		"hdmi1_pt_out cpr 8, , hdmi1_pt_out cpr 7"
+		"hdmi1_pt_out cpr 7, , HDMI1 Playback"
+		"iDisp1_out, , hdmi1_pt_out cpr 8"
+		"hdmi2_pt_out cpr 10, , hdmi2_pt_out cpr 9"
+		"hdmi2_pt_out cpr 9, , HDMI2 Playback"
+		"iDisp2_out, , hdmi2_pt_out cpr 10"
+		"hdmi3_pt_out cpr 12, , hdmi3_pt_out cpr 11"
+		"hdmi3_pt_out cpr 11, , HDMI3 Playback"
+		"iDisp1_out, , hdmi3_pt_out cpr 12"
+	]
+}
+
-- 
2.5.5

From a8ca6d1c4b942616dad43d51d954c31894e3c608 Mon Sep 17 00:00:00 2001
From: Shreyas NC <shreyas.nc@intel.com>
Date: Thu, 28 Apr 2016 11:07:57 +0530
Subject: [PATCH 13/34] Add u8 in type_compat.h

Skylake headers use u8 data types which were not present in
type_compat so add them.

Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/type_compat.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/sound/type_compat.h b/include/sound/type_compat.h
index eec86e4..e973ff3 100644
--- a/include/sound/type_compat.h
+++ b/include/sound/type_compat.h
@@ -32,9 +32,11 @@ typedef int32_t __s32;
 #define __le64 __u64
 #define __le32 __u32
 #define __le16 __u16
+#define __le8  __u8
 #define __be64 __u64
 #define __be32 __u32
 #define __be16 __u16
+#define __be8  __u8
 #endif /* DOC_HIDDEN */
 
 #endif /* __TYPE_COMPAT_H */
-- 
2.5.5

From 65b271034a36580badc980b3ff0bd77e7b9837ce Mon Sep 17 00:00:00 2001
From: Shreyas NC <shreyas.nc@intel.com>
Date: Thu, 28 Apr 2016 11:07:58 +0530
Subject: [PATCH 14/34] conf: topology: Generate Private data binary blobs

The DSP modules need private data and that is provided as binary
blob. These blobs are compiled from C structures which specify module
configuration.

Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 configure.ac                                       |    1 +
 src/conf/topology/sklrt286/Makefile.am             |    1 +
 src/conf/topology/sklrt286/data/Makefile.am        |    4 +
 src/conf/topology/sklrt286/data/pvt.c              | 1815 ++++++++++++++++++++
 src/conf/topology/sklrt286/data/pvt_data.c         |   90 +
 src/conf/topology/sklrt286/data/pvt_local.h        |    9 +
 .../topology/sklrt286/data/skl-tplg-interface.h    |  232 +++
 7 files changed, 2152 insertions(+)
 create mode 100644 src/conf/topology/sklrt286/data/Makefile.am
 create mode 100644 src/conf/topology/sklrt286/data/pvt.c
 create mode 100644 src/conf/topology/sklrt286/data/pvt_data.c
 create mode 100644 src/conf/topology/sklrt286/data/pvt_local.h
 create mode 100644 src/conf/topology/sklrt286/data/skl-tplg-interface.h

diff --git a/configure.ac b/configure.ac
index 1bf75e6..28fcd24 100644
--- a/configure.ac
+++ b/configure.ac
@@ -661,6 +661,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/conf/topology/Makefile \
 	  src/conf/topology/broadwell/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
+	  src/conf/topology/sklrt286/data/Makefile \
 	  src/conf/topology/sklrt286/Makefile \
 	  alsalisp/Makefile aserver/Makefile \
 	  test/Makefile test/lsb/Makefile \
diff --git a/src/conf/topology/sklrt286/Makefile.am b/src/conf/topology/sklrt286/Makefile.am
index facc508..ed58b77 100644
--- a/src/conf/topology/sklrt286/Makefile.am
+++ b/src/conf/topology/sklrt286/Makefile.am
@@ -1,4 +1,5 @@
 alsaconfigdir = @ALSA_CONFIG_DIR@
+SUBDIRS = data
 sklrt286dir = $(alsaconfigdir)/topology/sklrt286
 sklrt286_DATA = skl_i2s.conf media0_in-cpr-0.bin media0_in-mi.bin media0_out-mo.bin media0_out-cpr-6.bin codec0_out-mo.bin codec0_out-cpr-4.bin codec1_out-mo.bin codec1_out-cpr-5.bin codec0_in-cpr-1.bin codec0_in-mi.bin dmic01_hifi_in-cpr-3.bin dmic01_hifi_in-mi.bin hdmi1_pt_out-cpr-7.bin hdmi1_pt_out-cpr-8.bin hdmi2_pt_out-cpr-9.bin hdmi2_pt_out-cpr-10.bin hdmi3_pt_out-cpr-11.bin hdmi3_pt_out-cpr-12.bin 
 EXTRA_DIST = $(sklrt286_DATA)
diff --git a/src/conf/topology/sklrt286/data/Makefile.am b/src/conf/topology/sklrt286/data/Makefile.am
new file mode 100644
index 0000000..888ce16
--- /dev/null
+++ b/src/conf/topology/sklrt286/data/Makefile.am
@@ -0,0 +1,4 @@
+noinst_PROGRAMS = pvt_data
+pvt_data_SOURCES = pvt_data.c
+AM_CPPFLAGS = \
+         -Wall -I$(top_srcdir)/include
diff --git a/src/conf/topology/sklrt286/data/pvt.c b/src/conf/topology/sklrt286/data/pvt.c
new file mode 100644
index 0000000..3447e3e
--- /dev/null
+++ b/src/conf/topology/sklrt286/data/pvt.c
@@ -0,0 +1,1815 @@
+/*
+* Copyright(c) 2014-2016 Intel Corporation
+* All rights reserved.
+*
+* 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 of the License, or (at your option) any later version.
+
+* This library 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: Shreyas Nc <shreyas.nc@intel.com>
+*
+*/
+#include "pvt_local.h"
+
+struct skl_dfw_module_mod dfw_wrap[] = {
+{
+.name = "media0_in cpr 0",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 0,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 5,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 1,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "media0_in mi",
+.skl_dfw_mod = {
+	.uuid = {178, 110, 101, 57, 113, 59, 73, 64, 141, 63, 249, 44, 213, 196, 60, 9},
+	.module_id = 1,
+	.instance_id = 0,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 1,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "media0_out mo",
+.skl_dfw_mod = {
+	.uuid = {90, 80, 86, 60, 215, 36, 143, 65, 189, 220, 193, 245, 163, 172, 42, 224},
+	.module_id = 2,
+	.instance_id = 2,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 8,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 2,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "media0_out cpr 6",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 6,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 0,
+	.dev_type = 5,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 2,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec0_out mo",
+.skl_dfw_mod = {
+	.uuid = {90, 80, 86, 60, 215, 36, 143, 65, 189, 220, 193, 245, 163, 172, 42, 224},
+	.module_id = 2,
+	.instance_id = 0,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 8,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 3,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x4,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec0_out cpr 4",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 4,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = 0,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 2,
+	.dev_type = 2,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 3,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x4,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec1_out mo",
+.skl_dfw_mod = {
+	.uuid = {90, 80, 86, 60, 215, 36, 143, 65, 189, 220, 193, 245, 163, 172, 42, 224},
+	.module_id = 2,
+	.instance_id = 1,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 8,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 4,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec1_out cpr 5",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 5,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = 0,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 2,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 2,
+	.dev_type = 2,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 4,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec0_in cpr 1",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 1,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = 0,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 2,
+	.dev_type = 2,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 5,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "codec0_in mi",
+.skl_dfw_mod = {
+	.uuid = {178, 110, 101, 57, 113, 59, 73, 64, 141, 63, 249, 44, 213, 196, 60, 9},
+	.module_id = 1,
+	.instance_id = 1,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 5,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "dmic01_hifi_in cpr 3",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 3,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = 0,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 2,
+	.dev_type = 1,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 4,
+	.converter = 4,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 6,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "dmic01_hifi_in mi",
+.skl_dfw_mod = {
+	.uuid = {178, 110, 101, 57, 113, 59, 73, 64, 141, 63, 249, 44, 213, 196, 60, 9},
+	.module_id = 1,
+	.instance_id = 3,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 1,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 0,
+	.conn_type = 0,
+	.dev_type = 6,
+	.hw_conn_type = 2,
+	.rsvd2 = 0,
+	.params_fixup = 0,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 6,
+		.pipe_priority = 0,
+		.conn_type = 2,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi1_pt_out cpr 7",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 7,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 5,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 7,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi1_pt_out cpr 8",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 8,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 4,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 7,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi2_pt_out cpr 9",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 9,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 5,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 8,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi2_pt_out cpr 10",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 10,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 4,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 8,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi3_pt_out cpr 11",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 11,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 5,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 9,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 32,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+{
+.name = "hdmi3_pt_out cpr 12",
+.skl_dfw_mod = {
+	.uuid = {131, 12, 160, 155, 18, 202, 131, 74, 148, 60, 31, 162, 232, 47, 157, 218},
+	.module_id = 3,
+	.instance_id = 12,
+	.max_mcps = 0x186a0,
+	.mem_pages = 0x1,
+	.obs = 384,
+	.ibs = 384,
+	.vbus_id = -1,
+	.max_in_queue = 1,
+	.max_out_queue = 2,
+	.time_slot = 0,
+	.core_id = 0,
+	.rsvd1 = 0,
+	.module_type = 1,
+	.conn_type = 1,
+	.dev_type = 4,
+	.hw_conn_type = 1,
+	.rsvd2 = 0,
+	.params_fixup = 7,
+	.converter = 0,
+	.input_pin_type = 0,
+	.output_pin_type = 0,
+	.is_dynamic_in_pin = 1,
+	.is_dynamic_out_pin = 1,
+	.is_loadable = 0,
+	.rsvd3 = 0,
+	.pipe = {
+		.pipe_id = 9,
+		.pipe_priority = 0,
+		.conn_type = 1,
+		.rsvd = 0,
+		.memory_pages = 0x2,
+	},
+	.in_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.out_fmt = {
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+		{
+			.channels = 2,
+			.freq = 48000,
+			.bit_depth = 32,
+			.valid_bit_depth = 24,
+			.ch_cfg = 1,
+			.interleaving_style = 0,
+			.sample_type = 0,
+			.ch_map = 0xffffff10,
+		},
+	},
+	.in_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	.out_pin = {
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+		{
+			.module_id = 0,
+			.instance_id = 0,
+		},
+	},
+	},
+},
+	};
diff --git a/src/conf/topology/sklrt286/data/pvt_data.c b/src/conf/topology/sklrt286/data/pvt_data.c
new file mode 100644
index 0000000..dd55c3a
--- /dev/null
+++ b/src/conf/topology/sklrt286/data/pvt_data.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright(c) 2014-2016 Intel Corporation
+ * All rights reserved.
+ *
+ *  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 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ * Authors: Shreyas Nc <shreyas.nc@intel.com>
+ *
+ */
+#include "pvt.c"
+#include "stdio.h"
+#include "fcntl.h"
+#include <local.h>
+#include <limits.h>
+#include <stdint.h>
+#include <linux/types.h>
+#include "global.h"
+#include "list.h"
+
+#include <sound/asound.h>
+#include <sound/asoc.h>
+
+int replace_space(char *path, char *newpath)
+{
+	char buffer[52];
+	char *p;
+
+	strcpy(buffer, path);
+
+	while ((p = strchr(buffer, ' ')))
+		p[0] = '-';
+
+	strcpy(newpath, buffer);
+	return 0;
+}
+
+/*
+ * The private data structures are written into a
+ * binary blob. These contain module private data
+ * information
+ */
+int main(void)
+{
+	unsigned int i;
+	FILE  *fd;
+	char path[128];
+	char new_path[128];
+	struct snd_soc_tplg_private *priv = NULL;
+
+	memset(path, 0, sizeof(path));
+	memset(new_path, 0, sizeof(new_path));
+
+	priv = calloc(1, sizeof(dfw_wrap) + sizeof(uint32_t));
+
+	for (i = 0; i < ARRAY_SIZE(dfw_wrap); i++) {
+		strcat(path, "../");
+		strcat(path, dfw_wrap[i].name);
+		strcat(path, ".bin");
+
+		replace_space(path, new_path);
+
+		priv->size = (uint32_t)sizeof(dfw_wrap[i].skl_dfw_mod);
+
+		memcpy(priv->data, &dfw_wrap[i].skl_dfw_mod,
+				priv->size);
+
+		fd = fopen(new_path, "wb");
+
+		if (fd == NULL)
+			return -ENOENT;
+
+		if (fwrite(priv->data, priv->size, 1, fd) != 1) {
+			fclose(fd);
+			return -1;
+		}
+
+		memset(path, 0, sizeof(path));
+	}
+
+	free(priv);
+	return 0;
+}
diff --git a/src/conf/topology/sklrt286/data/pvt_local.h b/src/conf/topology/sklrt286/data/pvt_local.h
new file mode 100644
index 0000000..5edf7bd
--- /dev/null
+++ b/src/conf/topology/sklrt286/data/pvt_local.h
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include "skl-tplg-interface.h"
+
+struct skl_dfw_module_mod {
+	char name[100];
+	struct skl_dfw_module skl_dfw_mod;
+};
+
+
diff --git a/src/conf/topology/sklrt286/data/skl-tplg-interface.h b/src/conf/topology/sklrt286/data/skl-tplg-interface.h
new file mode 100644
index 0000000..e7389bc
--- /dev/null
+++ b/src/conf/topology/sklrt286/data/skl-tplg-interface.h
@@ -0,0 +1,232 @@
+/*
+ * skl-tplg-interface.h - Intel DSP FW private data interface
+ *
+ * Copyright (C) 2015 Intel Corp
+ * Author: Jeeja KP <jeeja.kp@intel.com>
+ *	    Nilofer, Samreen <samreen.nilofer@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as version 2, 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.
+ */
+
+#ifndef __HDA_TPLG_INTERFACE_H__
+#define __HDA_TPLG_INTERFACE_H__
+
+#include <sound/type_compat.h>
+/*
+ * Default types range from 0~12. type can range from 0 to 0xff
+ * SST types start at higher to avoid any overlapping in future
+ */
+#define SKL_CONTROL_TYPE_BYTE_TLV	0x100
+
+#define HDA_SST_CFG_MAX	900 /* size of copier cfg*/
+#define MAX_IN_QUEUE 8
+#define MAX_OUT_QUEUE 8
+
+#define SKL_UUID_STR_SZ 40
+/* Event types goes here */
+/* Reserve event type 0 for no event handlers */
+enum skl_event_types {
+	SKL_EVENT_NONE = 0,
+	SKL_MIXER_EVENT,
+	SKL_MUX_EVENT,
+	SKL_VMIXER_EVENT,
+	SKL_PGA_EVENT
+};
+
+/**
+ * enum skl_ch_cfg - channel configuration
+ *
+ * @SKL_CH_CFG_MONO:	One channel only
+ * @SKL_CH_CFG_STEREO:	L & R
+ * @SKL_CH_CFG_2_1:	L, R & LFE
+ * @SKL_CH_CFG_3_0:	L, C & R
+ * @SKL_CH_CFG_3_1:	L, C, R & LFE
+ * @SKL_CH_CFG_QUATRO:	L, R, Ls & Rs
+ * @SKL_CH_CFG_4_0:	L, C, R & Cs
+ * @SKL_CH_CFG_5_0:	L, C, R, Ls & Rs
+ * @SKL_CH_CFG_5_1:	L, C, R, Ls, Rs & LFE
+ * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
+ * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
+ * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
+ * @SKL_CH_CFG_INVALID:	Invalid
+ */
+enum skl_ch_cfg {
+	SKL_CH_CFG_MONO = 0,
+	SKL_CH_CFG_STEREO = 1,
+	SKL_CH_CFG_2_1 = 2,
+	SKL_CH_CFG_3_0 = 3,
+	SKL_CH_CFG_3_1 = 4,
+	SKL_CH_CFG_QUATRO = 5,
+	SKL_CH_CFG_4_0 = 6,
+	SKL_CH_CFG_5_0 = 7,
+	SKL_CH_CFG_5_1 = 8,
+	SKL_CH_CFG_DUAL_MONO = 9,
+	SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
+	SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
+	SKL_CH_CFG_4_CHANNEL = 12,
+	SKL_CH_CFG_INVALID
+};
+
+enum skl_module_type {
+	SKL_MODULE_TYPE_MIXER = 0,
+	SKL_MODULE_TYPE_COPIER,
+	SKL_MODULE_TYPE_UPDWMIX,
+	SKL_MODULE_TYPE_SRCINT,
+	SKL_MODULE_TYPE_ALGO,
+	SKL_MODULE_TYPE_BASE_OUTFMT
+};
+
+enum skl_core_affinity {
+	SKL_AFFINITY_CORE_0 = 0,
+	SKL_AFFINITY_CORE_1,
+	SKL_AFFINITY_CORE_MAX
+};
+
+enum skl_pipe_conn_type {
+	SKL_PIPE_CONN_TYPE_NONE = 0,
+	SKL_PIPE_CONN_TYPE_FE,
+	SKL_PIPE_CONN_TYPE_BE
+};
+
+enum skl_hw_conn_type {
+	SKL_CONN_NONE = 0,
+	SKL_CONN_SOURCE = 1,
+	SKL_CONN_SINK = 2
+};
+
+enum skl_dev_type {
+	SKL_DEVICE_BT = 0x0,
+	SKL_DEVICE_DMIC = 0x1,
+	SKL_DEVICE_I2S = 0x2,
+	SKL_DEVICE_SLIMBUS = 0x3,
+	SKL_DEVICE_HDALINK = 0x4,
+	SKL_DEVICE_HDAHOST = 0x5,
+	SKL_DEVICE_NONE
+};
+
+/**
+ * enum skl_interleaving - interleaving style
+ *
+ * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
+ * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
+ */
+enum skl_interleaving {
+	SKL_INTERLEAVING_PER_CHANNEL = 0,
+	SKL_INTERLEAVING_PER_SAMPLE = 1,
+};
+
+enum skl_sample_type {
+	SKL_SAMPLE_TYPE_INT_MSB = 0,
+	SKL_SAMPLE_TYPE_INT_LSB = 1,
+	SKL_SAMPLE_TYPE_INT_SIGNED = 2,
+	SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
+	SKL_SAMPLE_TYPE_FLOAT = 4
+};
+
+enum module_pin_type {
+	/* All pins of the module takes same PCM inputs or outputs
+	* e.g. mixout
+	*/
+	SKL_PIN_TYPE_HOMOGENEOUS,
+	/* All pins of the module takes different PCM inputs or outputs
+	* e.g mux
+	*/
+	SKL_PIN_TYPE_HETEROGENEOUS,
+};
+
+enum skl_module_param_type {
+	SKL_PARAM_DEFAULT = 0,
+	SKL_PARAM_INIT,
+	SKL_PARAM_SET,
+	SKL_PARAM_BIND
+};
+
+struct skl_dfw_module_pin {
+	__le16 module_id;
+	__le16 instance_id;
+} __attribute__((packed));
+
+struct skl_dfw_module_fmt {
+	__le32 channels;
+	__le32 freq;
+	__le32 bit_depth;
+	__le32 valid_bit_depth;
+	__le32 ch_cfg;
+	__le32 interleaving_style;
+	__le32 sample_type;
+	__le32 ch_map;
+} __attribute__((packed));
+
+struct skl_dfw_module_caps {
+	__le32 set_params:2;
+	__le32 rsvd:30;
+	__le32 param_id;
+	__le32 caps_size;
+	__le32 caps[HDA_SST_CFG_MAX];
+};
+
+struct skl_dfw_pipe {
+	__le8 pipe_id;
+	__le8 pipe_priority;
+	__le16 conn_type:4;
+	__le16 rsvd:4;
+	__le16 memory_pages:8;
+} __attribute__((packed));
+
+struct skl_dfw_module {
+	__le8 uuid[16];
+
+	__le16 module_id;
+	__le16 instance_id;
+	__le32 max_mcps;
+	__le32 mem_pages;
+	__le32 obs;
+	__le32 ibs;
+	__le32 vbus_id;
+
+	__le32 max_in_queue:8;
+	__le32 max_out_queue:8;
+	__le32 time_slot:8;
+	__le32 core_id:4;
+	__le32 rsvd1:4;
+
+	__le32 module_type:8;
+	__le32 conn_type:4;
+	__le32 dev_type:4;
+	__le32 hw_conn_type:4;
+	__le32 rsvd2:12;
+
+	__le32 params_fixup:8;
+	__le32 converter:8;
+	__le32 input_pin_type:1;
+	__le32 output_pin_type:1;
+	__le32 is_dynamic_in_pin:1;
+	__le32 is_dynamic_out_pin:1;
+	__le32 is_loadable:1;
+	__le32 rsvd3:11;
+
+	struct skl_dfw_pipe pipe;
+	struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE];
+	struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE];
+	struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE];
+	struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE];
+	struct skl_dfw_module_caps caps;
+} __attribute__((packed));
+
+struct skl_dfw_algo_data {
+	__le32 set_params:2;
+	__le32 rsvd:30;
+	__le32 param_id;
+	__le32 max;
+	char params[0];
+} __attribute__((packed));
+
+#endif
-- 
2.5.5

From e64334df2b2fe6756539178d89133a0b56e83c9d Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:02:57 +0800
Subject: [PATCH 16/34] topology: Set manifest size for ABI

The topology kernel driver will check the size of manifest struct, and
will stop loading topology info if size mismatch is detected.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/parser.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/topology/parser.c b/src/topology/parser.c
index 30d91f9..84117c3 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -414,6 +414,8 @@ snd_tplg_t *snd_tplg_new(void)
 	if (!tplg)
 		return NULL;
 
+	tplg->manifest.size = sizeof(struct snd_soc_tplg_manifest);
+
 	INIT_LIST_HEAD(&tplg->tlv_list);
 	INIT_LIST_HEAD(&tplg->widget_list);
 	INIT_LIST_HEAD(&tplg->pcm_list);
-- 
2.5.5

From 86ec8b49008fbcfa45756f7ab1803392c3bb464e Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:03:04 +0800
Subject: [PATCH 17/34] topology: Refactor functions to parse and build streams

Previously these functions are only used by pcm elements (front-end DAI
& DAI link) to parse stream capablities. Now refactor them to be reused
by back-end DAI elements later.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/parser.c     |  2 +-
 src/topology/pcm.c        | 60 +++++++++++++++++++++++++++--------------------
 src/topology/tplg_local.h |  2 +-
 3 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/src/topology/parser.c b/src/topology/parser.c
index 84117c3..f6fc944 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -119,7 +119,7 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
 
 		if (strcmp(id, "SectionPCMCapabilities") == 0) {
 			err = tplg_parse_compound(tplg, n,
-				tplg_parse_pcm_caps, NULL);
+				tplg_parse_stream_caps, NULL);
 			if (err < 0)
 				return err;
 			continue;
diff --git a/src/topology/pcm.c b/src/topology/pcm.c
index d75aad8..1df4f54 100644
--- a/src/topology/pcm.c
+++ b/src/topology/pcm.c
@@ -40,9 +40,9 @@ struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
 	return NULL;
 }
 
-/* copy referenced caps to the pcm */
-static void copy_pcm_caps(const char *id, struct snd_soc_tplg_stream_caps *caps,
-	struct tplg_elem *ref_elem)
+/* copy referenced caps to the parent (pcm or be dai) */
+static void copy_stream_caps(const char *id,
+	struct snd_soc_tplg_stream_caps *caps, struct tplg_elem *ref_elem)
 {
 	struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
 
@@ -52,24 +52,19 @@ static void copy_pcm_caps(const char *id, struct snd_soc_tplg_stream_caps *caps,
 	*caps =  *ref_caps;
 }
 
-/* check referenced config and caps for a pcm */
-static int tplg_build_pcm_caps(snd_tplg_t *tplg, struct tplg_elem *elem)
+/* find and copy the referenced stream caps */
+static int tplg_build_stream_caps(snd_tplg_t *tplg,
+	const char *id, struct snd_soc_tplg_stream_caps *caps)
 {
 	struct tplg_elem *ref_elem = NULL;
-	struct snd_soc_tplg_pcm *pcm;
-	struct snd_soc_tplg_stream_caps *caps;
 	unsigned int i;
 
-	pcm = elem->pcm;
-
 	for (i = 0; i < 2; i++) {
-		caps = &pcm->caps[i];
-
 		ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
-			caps->name, SND_TPLG_TYPE_STREAM_CAPS);
+			caps[i].name, SND_TPLG_TYPE_STREAM_CAPS);
 
 		if (ref_elem != NULL)
-			copy_pcm_caps(elem->id, caps, ref_elem);
+			copy_stream_caps(id, &caps[i], ref_elem);
 	}
 
 	return 0;
@@ -91,7 +86,7 @@ int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type)
 			return -EINVAL;
 		}
 
-		err = tplg_build_pcm_caps(tplg, elem);
+		err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps);
 		if (err < 0)
 			return err;
 
@@ -184,8 +179,8 @@ static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
 	return 0;
 }
 
-/* Parse pcm Capabilities */
-int tplg_parse_pcm_caps(snd_tplg_t *tplg,
+/* Parse pcm stream capabilities */
+int tplg_parse_stream_caps(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
 {
 	struct snd_soc_tplg_stream_caps *sc;
@@ -263,29 +258,40 @@ int tplg_parse_pcm_caps(snd_tplg_t *tplg,
 	return 0;
 }
 
-/* Parse the caps of a pcm stream */
-int tplg_parse_stream_caps(snd_tplg_t *tplg, snd_config_t *cfg,
+/* Parse the caps and config of a pcm stream */
+static int tplg_parse_streams(snd_tplg_t *tplg, snd_config_t *cfg,
 	void *private)
 {
 	snd_config_iterator_t i, next;
 	snd_config_t *n;
 	struct tplg_elem *elem = private;
 	struct snd_soc_tplg_pcm *pcm;
+	unsigned int *playback, *capture;
+	struct snd_soc_tplg_stream_caps *caps;
 	const char *id, *value;
 	int stream;
 
-	pcm = elem->pcm;
-
 	snd_config_get_id(cfg, &id);
 
 	tplg_dbg("\t%s:\n", id);
 
+	switch (elem->type) {
+	case SND_TPLG_TYPE_PCM:
+		pcm = elem->pcm;
+		playback = &pcm->playback;
+		capture = &pcm->capture;
+		caps = pcm->caps;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	if (strcmp(id, "playback") == 0) {
 		stream = SND_SOC_TPLG_STREAM_PLAYBACK;
-		pcm->playback = 1;
+		*playback = 1;
 	} else if (strcmp(id, "capture") == 0) {
 		stream = SND_SOC_TPLG_STREAM_CAPTURE;
-		pcm->capture = 1;
+		*capture = 1;
 	} else
 		return -EINVAL;
 
@@ -300,8 +306,10 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, snd_config_t *cfg,
 		if (strcmp(id, "capabilities") == 0) {
 			if (snd_config_get_string(n, &value) < 0)
 				continue;
-
-			elem_copy_text(pcm->caps[stream].name, value,
+			/* store stream caps name, to find and merge
+			 * the caps in building phase.
+			 */
+			elem_copy_text(caps[stream].name, value,
 				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
 
 			tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value);
@@ -312,7 +320,7 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, snd_config_t *cfg,
 	return 0;
 }
 
-/* Parse pcm */
+/* Parse pcm (for front end DAI & DAI link) */
 int tplg_parse_pcm(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
 {
@@ -365,7 +373,7 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
 
 		if (strcmp(id, "pcm") == 0) {
 			err = tplg_parse_compound(tplg, n,
-				tplg_parse_stream_caps, elem);
+				tplg_parse_streams, elem);
 			if (err < 0)
 				return err;
 			continue;
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 4c601d4..9239aef 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -210,7 +210,7 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
 int tplg_parse_dapm_widget(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
 
-int tplg_parse_pcm_caps(snd_tplg_t *tplg,
+int tplg_parse_stream_caps(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);
 
 int tplg_parse_pcm(snd_tplg_t *tplg,
-- 
2.5.5

From 0935e32d40e065e61255550ac4c5b7c6710dd028 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:03:22 +0800
Subject: [PATCH 18/34] topology: Use generic pointer to realloc buffer for
 private data

Many element types have private data. So use the generic obj pointer
instead of the type-specific pointer when reallocating the object to
accommodate the private data.

Empty private data will be overlooked.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/topology/data.c | 26 +++++++++-----------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/src/topology/data.c b/src/topology/data.c
index 19c31bf..9f8d5d0 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -822,44 +822,36 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
 {
 	struct snd_soc_tplg_private *priv;
 	int priv_data_size;
+	void *obj;
 
 	if (!ref)
 		return -EINVAL;
 
 	tplg_dbg("Data '%s' used by '%s'\n", ref->id, elem->id);
+	if (!ref->data || !ref->data->size) /* overlook empty private data */
+		return 0;
+
 	priv_data_size = ref->data->size;
+	obj = realloc(elem->obj,
+			elem->size + priv_data_size);
+	if (!obj)
+		return -ENOMEM;
+	elem->obj = obj;
 
 	switch (elem->type) {
 	case SND_TPLG_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 SND_TPLG_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 SND_TPLG_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 SND_TPLG_TYPE_DAPM_WIDGET:
-		elem->widget = realloc(elem->widget,
-			elem->size + priv_data_size);
-		if (!elem->widget)
-			return -ENOMEM;
 		priv = &elem->widget->priv;
 		break;
 
-- 
2.5.5

From 5d23c406d1757d1b65e1d17a71c69620d9af71d7 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:03:30 +0800
Subject: [PATCH 19/34] topology: Fix pcm ID & name parsing

The name and ID of SectionPCM should be set to pcm_name and pcm_id,
for a front-end DAI link in the kernel, not for the front-end DAI
of the link.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asoc.h | 2 +-
 src/topology/pcm.c   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/sound/asoc.h b/include/sound/asoc.h
index 920c9e0..abe49c5 100644
--- a/include/sound/asoc.h
+++ b/include/sound/asoc.h
@@ -414,7 +414,7 @@ struct snd_soc_tplg_pcm {
 	__le32 size;		/* in bytes of this structure */
 	char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 	char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-	__le32 pcm_id;		/* unique ID - used to match */
+	__le32 pcm_id;		/* unique ID - used to match with DAI link */
 	__le32 dai_id;		/* unique ID - used to match */
 	__le32 playback;	/* supports playback mode */
 	__le32 capture;		/* supports capture mode */
diff --git a/src/topology/pcm.c b/src/topology/pcm.c
index 1df4f54..1661821 100644
--- a/src/topology/pcm.c
+++ b/src/topology/pcm.c
@@ -337,7 +337,7 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
 
 	pcm = elem->pcm;
 	pcm->size = elem->size;
-	elem_copy_text(pcm->dai_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+	elem_copy_text(pcm->pcm_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
 
 	tplg_dbg(" PCM: %s\n", elem->id);
 
@@ -366,8 +366,8 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
 			if (snd_config_get_string(n, &val) < 0)
 				return -EINVAL;
 
-			pcm->dai_id = atoi(val);
-			tplg_dbg("\t%s: %d\n", id, pcm->dai_id);
+			pcm->pcm_id = atoi(val);
+			tplg_dbg("\t%s: %d\n", id, pcm->pcm_id);
 			continue;
 		}
 
-- 
2.5.5

From 25d6f8e6a8e162259dcf84600496dc8ebd8196e7 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:03:37 +0800
Subject: [PATCH 20/34] topology: Parse front-end DAI name and ID for the PCM

These two fields are necessary to create the front-end DAIs
in kernel but the support is missing in text conf previously.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/topology.h |  4 ++++
 src/topology/pcm.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/include/topology.h b/include/topology.h
index b47f422..9d57ce3 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -533,6 +533,10 @@ extern "C" {
  *
  *	id "0"				# used for binding to the PCM
  *
+ *	dai."name of front-end DAI" {
+ *		id "0"		# used for binding to the front-end DAI
+ *	}
+ *
  *	pcm."playback" {
  *		capabilities "capabilities1"	# capabilities for playback
  *
diff --git a/src/topology/pcm.c b/src/topology/pcm.c
index 1661821..efee58b 100644
--- a/src/topology/pcm.c
+++ b/src/topology/pcm.c
@@ -320,6 +320,51 @@ static int tplg_parse_streams(snd_tplg_t *tplg, snd_config_t *cfg,
 	return 0;
 }
 
+/* Parse name and id of a front-end DAI (ie. cpu dai of a FE DAI link) */
+static int tplg_parse_fe_dai(snd_tplg_t *tplg, snd_config_t *cfg,
+	void *private)
+{
+	struct tplg_elem *elem = private;
+	struct snd_soc_tplg_pcm *pcm = elem->pcm;
+	snd_config_iterator_t i, next;
+	snd_config_t *n;
+	const char *id, *value = NULL;
+	unsigned long int id_val;
+	int err;
+
+	snd_config_get_id(cfg, &id);
+	tplg_dbg("\t\tFE DAI %s:\n", id);
+	elem_copy_text(pcm->dai_name, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+
+	snd_config_for_each(i, next, cfg) {
+
+		n = snd_config_iterator_entry(i);
+
+		/* get id */
+		if (snd_config_get_id(n, &id) < 0)
+			continue;
+
+		if (strcmp(id, "id") == 0) {
+			if (snd_config_get_string(n, &value) < 0)
+				continue;
+			errno = 0;
+			/* no support for negative value */
+			id_val = strtoul(value, NULL, 0);
+			if ((errno == ERANGE && id_val == ULONG_MAX)
+				|| (errno != 0 && id_val == 0)
+				|| id_val > UINT_MAX) {
+				SNDERR("error: invalid fe dai ID\n");
+				return -EINVAL;
+			}
+
+			pcm->dai_id = (int) id_val;
+			tplg_dbg("\t\t\tindex: %d\n", pcm->dai_id);
+		}
+	}
+
+	return 0;
+}
+
 /* Parse pcm (for front end DAI & DAI link) */
 int tplg_parse_pcm(snd_tplg_t *tplg,
 	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
@@ -378,6 +423,14 @@ int tplg_parse_pcm(snd_tplg_t *tplg,
 				return err;
 			continue;
 		}
+
+		if (strcmp(id, "dai") == 0) {
+			err = tplg_parse_compound(tplg, n,
+				tplg_parse_fe_dai, elem);
+			if (err < 0)
+				return err;
+			continue;
+		}
 	}
 
 	return 0;
-- 
2.5.5

From 76af5bf833323d8ae1caa23d592a959e74990932 Mon Sep 17 00:00:00 2001
From: Mengdong Lin <mengdong.lin@linux.intel.com>
Date: Fri, 29 Apr 2016 11:03:45 +0800
Subject: [PATCH 21/34] topology: Update PCM configurations in Broadwell text
 conf file

To make this conf file a better example, update the name & ID of PCMs
(front-end DAI link) and their cpu DAI (front-end DAI), same as those
defined by Broadwell upstream driver.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/conf/topology/broadwell/broadwell.conf | 34 ++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/src/conf/topology/broadwell/broadwell.conf b/src/conf/topology/broadwell/broadwell.conf
index 05b3889..eb89377 100644
--- a/src/conf/topology/broadwell/broadwell.conf
+++ b/src/conf/topology/broadwell/broadwell.conf
@@ -272,18 +272,22 @@ SectionPCMCapabilities."Offload0 Playback" {
 SectionPCMCapabilities."Offload1 Playback" {
 	formats "S24_LE,S16_LE"
 	rate_min "8000"
-	rate_max "48000"
+	rate_max "192000"
 	channels_min "2"
 	channels_max "2"
 }
 
 # PCM devices exported by Firmware
-SectionPCM."System Pin" {
+SectionPCM."System Playback/Capture" {
 
 	index "1"
 
 	# used for binding to the PCM
-	ID "0"
+	id "0"
+
+	dai."System Pin" {
+		id "0"
+	}
 
 	pcm."playback" {
 
@@ -307,12 +311,16 @@ SectionPCM."System Pin" {
 	}
 }
 
-SectionPCM."Offload0 Pin" {
+SectionPCM."Offload0 Playback" {
 
 	index "1"
 
 	# used for binding to the PCM
-	ID "1"
+	id "1"
+
+	dai."Offload0 Pin" {
+		id "1"
+	}
 
 	pcm."playback" {
 
@@ -325,12 +333,16 @@ SectionPCM."Offload0 Pin" {
 	}
 }
 
-SectionPCM."Offload1 Pin" {
+SectionPCM."Offload1 Playback" {
 
 	index "1"
 
 	# used for binding to the PCM
-	ID "2"
+	id "2"
+
+	dai."Offload1 Pin" {
+		id "2"
+	}
 
 	pcm."playback" {
 
@@ -343,12 +355,16 @@ SectionPCM."Offload1 Pin" {
 	}
 }
 
-SectionPCM."Loopback Pin" {
+SectionPCM."Loopback PCM" {
 
 	index "1"
 
 	# used for binding to the PCM
-	ID "3"
+	id "3"
+
+	dai."Loopback Pin" {
+		id "3"
+	}
 
 	pcm."capture" {
 
-- 
2.5.5

From 85bf9915989e0a338632739684c75192c1753239 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Krause?= <joerg.krause@embedded.rocks>
Date: Sun, 8 May 2016 20:48:42 +0200
Subject: [PATCH 22/34] pcm: softvol: fix conversion of TLVs min_db and max_dB
 value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Both, min_dB and max_dB, are floating type whereas the TLV is (always)
unsigned.

The problem with the conversion of a negative floating-point number into an
unsigned integer is, that the behavior is undefined. This may, depending on
the platform, result in a wrong TLV, i.e. for the default values of min_dB
(-51dB) and max_dB (0dB), alsactl generates the following state on an ARM
cpu build with GCC:

	control.1 {
                iface MIXER
                name Master
                value.0 255
                value.1 255
                comment {
                        access 'read write user'
                        type INTEGER
                        count 2
                        range '0 - 255'
                        tlv '00000001000000080000000000000014'
                        dbmin 0
                        dbmax 5100
                        dbvalue.0 5100
                        dbvalue.1 5100
                }
        }

With the fix applied, alsactl stores the correct TLV:

	control.1 {
                iface MIXER
                name Master
                value.0 255
                value.1 255
                comment {
                        access 'read write user'
                        type INTEGER
                        count 2
                        range '0 - 255'
                        tlv '0000000100000008ffffec1400000014'
                        dbmin -5100
                        dbmax 0
                        dbvalue.0 0
                        dbvalue.1 0
                }
        }

Also tested for different combinations of min_dB and max_dB other than the
default values.

Replaces:
http://mailman.alsa-project.org/pipermail/alsa-devel/2016-May/107733.html

Fixes:
http://mailman.alsa-project.org/pipermail/alsa-devel/2016-May/107628.html

Cc: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_softvol.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c
index 802aa4b..5492db8 100644
--- a/src/pcm/pcm_softvol.c
+++ b/src/pcm/pcm_softvol.c
@@ -658,8 +658,8 @@ static int add_tlv_info(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo)
 	unsigned int tlv[4];
 	tlv[0] = SND_CTL_TLVT_DB_SCALE;
 	tlv[1] = 2 * sizeof(int);
-	tlv[2] = svol->min_dB * 100;
-	tlv[3] = (svol->max_dB - svol->min_dB) * 100 / svol->max_val;
+	tlv[2] = (int)(svol->min_dB * 100);
+	tlv[3] = (int)((svol->max_dB - svol->min_dB) * 100 / svol->max_val);
 	return snd_ctl_elem_tlv_write(svol->ctl, &cinfo->id, tlv);
 }
 
-- 
2.5.5

From a192f52fc63a86e1fbb9a09adb0bc2a6bbc8dab1 Mon Sep 17 00:00:00 2001
From: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Date: Thu, 5 May 2016 08:32:06 +0200
Subject: [PATCH 23/34] conf/ucm: ROCKCHIP-I2S: add Rockchip I2S UCM config.

Taken from the ChromeOS sources, this configuration was tested on Veyron
Jerry based Chromebook from Google.

[Added missing Makefile changes by tiwai]

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 configure.ac                                |  1 +
 src/conf/ucm/Makefile.am                    |  2 +-
 src/conf/ucm/ROCKCHIP-I2S/HiFi.conf         | 94 +++++++++++++++++++++++++++++
 src/conf/ucm/ROCKCHIP-I2S/Makefile.am       |  4 ++
 src/conf/ucm/ROCKCHIP-I2S/ROCKCHIP-I2S.conf |  6 ++
 5 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 src/conf/ucm/ROCKCHIP-I2S/HiFi.conf
 create mode 100644 src/conf/ucm/ROCKCHIP-I2S/Makefile.am
 create mode 100644 src/conf/ucm/ROCKCHIP-I2S/ROCKCHIP-I2S.conf

diff --git a/configure.ac b/configure.ac
index 28fcd24..ff340a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -658,6 +658,7 @@ 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/ucm/ROCKCHIP-I2S/Makefile \
 	  src/conf/topology/Makefile \
 	  src/conf/topology/broadwell/Makefile \
 	  modules/Makefile modules/mixer/Makefile modules/mixer/simple/Makefile \
diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am
index e6a6325..d1d51e5 100644
--- a/src/conf/ucm/Makefile.am
+++ b/src/conf/ucm/Makefile.am
@@ -1 +1 @@
-SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286
+SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 ROCKCHIP-I2S
diff --git a/src/conf/ucm/ROCKCHIP-I2S/HiFi.conf b/src/conf/ucm/ROCKCHIP-I2S/HiFi.conf
new file mode 100644
index 0000000..7bfe995
--- /dev/null
+++ b/src/conf/ucm/ROCKCHIP-I2S/HiFi.conf
@@ -0,0 +1,94 @@
+SectionVerb {
+	Value {
+		OutputDspName "speaker_eq"
+		MinBufferLevel "512"
+	}
+
+	EnableSequence [
+		cdev "hw:ROCKCHIPI2S"
+
+		cset "name='Left Speaker Mixer Left DAC Switch' on"
+		cset "name='Right Speaker Mixer Right DAC Switch' on"
+		cset "name='Headphone Left Switch' off"
+		cset "name='Headphone Right Switch' off"
+		cset "name='Digital EQ 3 Band Switch' off"
+		cset "name='Digital EQ 5 Band Switch' off"
+		cset "name='Digital EQ 7 Band Switch' off"
+		cset "name='Biquad Switch' off"
+		cset "name='Filter Mode' Music"
+		cset "name='ADC Oversampling Rate' 0"
+
+		cset "name='DMIC Mux' DMIC"
+		cset "name='MIC2 Mux' IN34"
+		cset "name='Right ADC Mixer MIC2 Switch' on"
+		cset "name='Left ADC Mixer MIC2 Switch' on"
+		cset "name='MIC2 Volume' 20"
+		cset "name='Headset Mic Switch' off"
+		cset "name='Int Mic Switch' on"
+
+		cset "name='ADCR Boost Volume' 4"
+		cset "name='ADCL Boost Volume' 4"
+		cset "name='ADCR Volume' 11"
+		cset "name='ADCL Volume' 11"
+
+		cset "name='Left Speaker Mixer Left DAC Switch' on"
+		cset "name='Right Speaker Mixer Right DAC Switch' on"
+		cset "name='Speaker Left Mixer Volume' 2"
+		cset "name='Speaker Right Mixer Volume' 2"
+		cset "name='Record Path DC Blocking' on"
+		cset "name='Playback Path DC Blocking' on"
+
+		cset "name='Speaker Left Switch' on"
+		cset "name='Speaker Right Switch' on"
+		cset "name='Speaker Switch' on"
+	]
+
+	DisableSequence [
+	]
+}
+
+SectionDevice."Headphone".0 {
+	Value {
+		JackName "ROCKCHIP-I2S Headset Jack"
+		OutputDspName ""
+	}
+
+	EnableSequence [
+		cdev "hw:ROCKCHIPI2S"
+
+		cset "name='Speaker Switch' off"
+		cset "name='Headphone Left Switch' on"
+		cset "name='Headphone Right Switch' on"
+	]
+	DisableSequence [
+		cdev "hw:ROCKCHIPI2S"
+
+		cset "name='Headphone Left Switch' off"
+		cset "name='Headphone Right Switch' off"
+		cset "name='Speaker Switch' on"
+	]
+}
+
+SectionDevice."Mic".0 {
+	Value {
+		JackName "ROCKCHIP-I2S Headset Jack"
+	}
+
+	EnableSequence [
+		cdev "hw:ROCKCHIPI2S"
+
+		cset "name='Int Mic Switch' off"
+		cset "name='DMIC Mux' ADC"
+		cset "name='Headset Mic Switch' on"
+		cset "name='Record Path DC Blocking' on"
+	]
+
+	DisableSequence [
+		cdev "hw:ROCKCHIPI2S"
+
+		cset "name='Headset Mic Switch' off"
+		cset "name='DMIC Mux' DMIC"
+		cset "name='Int Mic Switch' on"
+		cset "name='Record Path DC Blocking' off"
+	]
+}
diff --git a/src/conf/ucm/ROCKCHIP-I2S/Makefile.am b/src/conf/ucm/ROCKCHIP-I2S/Makefile.am
new file mode 100644
index 0000000..485a740
--- /dev/null
+++ b/src/conf/ucm/ROCKCHIP-I2S/Makefile.am
@@ -0,0 +1,4 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+ucmdir = $(alsaconfigdir)/ucm/ROCKCHIP-I2S
+ucm_DATA = ROCKCHIP-I2S.conf HiFi.conf
+EXTRA_DIST = $(ucm_DATA)
diff --git a/src/conf/ucm/ROCKCHIP-I2S/ROCKCHIP-I2S.conf b/src/conf/ucm/ROCKCHIP-I2S/ROCKCHIP-I2S.conf
new file mode 100644
index 0000000..0c399b0
--- /dev/null
+++ b/src/conf/ucm/ROCKCHIP-I2S/ROCKCHIP-I2S.conf
@@ -0,0 +1,6 @@
+Comment "Rockchip card"
+
+SectionUseCase."HiFi" {
+	File "HiFi.conf"
+	Comment "Default"
+}
-- 
2.5.5

From c14b0a08f0bf58e4f62307c68f8ff0137b4dec19 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 11 May 2016 09:06:47 +0200
Subject: [PATCH 24/34] pcm: Fix suspend/resume regression with dmix & co

The recent fix commit [8985742d91db: pcm: dmix: Handle slave PCM xrun
and unexpected states properly] caused a regression in dmix and other
plugins regarding suspend/resume.  For example, aplay endlessly prints
"Suspended. Trying resume. Done." message if suspend and resume are
performed in the middle of playback.

The reason is that the commit above changed the shadow PCM state
(dmix->state) to SUSPENDED when the slave PCM is in suspend, while it
doesn't restore the shadow state upon resume.  Thus it appears as if
it's always suspended even after the resume is invoked.

The fix is just to add the proper update of the shadow state in
snd_pcm_direct_resume().

Reported-by: Shengjiu Wang <shengjiu.wang@freescale.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_direct.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 14de734..e28738b 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -848,6 +848,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 		snd_pcm_start(dmix->spcm);
 		err = 0;
 	}
+	dmix->state = snd_pcm_state(dmix->spcm);
 	snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
 	return err;
 }
-- 
2.5.5

From 5610b356b5f110f7f8e586f56e5b74e0f0c2db38 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 11 May 2016 13:06:25 +0200
Subject: [PATCH 25/34] pcm: dmix: Fix doubly resume of slave PCM

The dmix plugin and co may trigger the resume for each instance in
snd_pcm_direct_resume().  It means that the slave PCM gets resumed or
re-prepared/started by each opened dmix stream, and this may end up
with the doubly triggers even though the slave PCM has been already
resumed by another dmix stream.

For avoiding this conflicts, check the slave PCM state and resume only
when it's still in the suspended state.  Meanwhile we keep the shadow
state updated no matter whether the slave was triggered or not.

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

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index e28738b..ac082f1 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -841,6 +841,12 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 	int err;
 	
 	snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+	/* resume only when the slave PCM is still in suspended state */
+	if (snd_pcm_state(dmix->spcm) != SND_PCM_STATE_SUSPENDED) {
+		err = 0;
+		goto out;
+	}
+
 	err = snd_pcm_resume(dmix->spcm);
 	if (err == -ENOSYS) {
 		/* FIXME: error handling? */
@@ -848,6 +854,7 @@ int snd_pcm_direct_resume(snd_pcm_t *pcm)
 		snd_pcm_start(dmix->spcm);
 		err = 0;
 	}
+ out:
 	dmix->state = snd_pcm_state(dmix->spcm);
 	snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
 	return err;
-- 
2.5.5

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

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

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

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

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

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

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

diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf
index e62cb29..7d0aa01 100644
--- a/src/conf/pcm/dmix.conf
+++ b/src/conf/pcm/dmix.conf
@@ -110,6 +110,6 @@ pcm.!dmix {
 			name defaults.namehint.extended
 		}
 		description "Direct sample mixing device"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/dsnoop.conf b/src/conf/pcm/dsnoop.conf
index 49cfca9..abbd44f 100644
--- a/src/conf/pcm/dsnoop.conf
+++ b/src/conf/pcm/dsnoop.conf
@@ -110,6 +110,6 @@ pcm.!dsnoop {
 			name defaults.namehint.extended
 		}
 		description "Direct sample snooping device"
-		device $DEV
+		device_input $DEV
 	}
 }
diff --git a/src/conf/pcm/surround21.conf b/src/conf/pcm/surround21.conf
index 7f4676b..1cf1b7a 100644
--- a/src/conf/pcm/surround21.conf
+++ b/src/conf/pcm/surround21.conf
@@ -56,6 +56,6 @@ pcm.!surround21 {
 	ttable.2.LFE 1
 	hint {
 		description "2.1 Surround output to Front and Subwoofer speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/surround40.conf b/src/conf/pcm/surround40.conf
index 361ccaa..9788ad4 100644
--- a/src/conf/pcm/surround40.conf
+++ b/src/conf/pcm/surround40.conf
@@ -54,6 +54,6 @@ pcm.!surround40 {
 	}
 	hint {
 		description "4.0 Surround output to Front and Rear speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/surround41.conf b/src/conf/pcm/surround41.conf
index 2f82381..7b4ef3b 100644
--- a/src/conf/pcm/surround41.conf
+++ b/src/conf/pcm/surround41.conf
@@ -60,6 +60,6 @@ pcm.!surround41 {
 	ttable.4.LFE 1
 	hint {
 		description "4.1 Surround output to Front, Rear and Subwoofer speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/surround50.conf b/src/conf/pcm/surround50.conf
index dc95c17..7d9a9e7 100644
--- a/src/conf/pcm/surround50.conf
+++ b/src/conf/pcm/surround50.conf
@@ -60,6 +60,6 @@ pcm.!surround50 {
 	ttable.4.FC 1
 	hint {
 		description "5.0 Surround output to Front, Center and Rear speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/surround51.conf b/src/conf/pcm/surround51.conf
index 3a7543f..e67f007 100644
--- a/src/conf/pcm/surround51.conf
+++ b/src/conf/pcm/surround51.conf
@@ -56,6 +56,6 @@ pcm.!surround51 {
 	}
 	hint {
 		description "5.1 Surround output to Front, Center, Rear and Subwoofer speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
diff --git a/src/conf/pcm/surround71.conf b/src/conf/pcm/surround71.conf
index 076a97d..a26c3f3 100644
--- a/src/conf/pcm/surround71.conf
+++ b/src/conf/pcm/surround71.conf
@@ -58,6 +58,6 @@ pcm.!surround71 {
 	}
 	hint {
 		description "7.1 Surround output to Front, Center, Side, Rear and Woofer speakers"
-		device $DEV
+		device_output $DEV
 	}
 }
-- 
2.5.5

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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