From b63a8447acfc4e09b5018357aaa85752804024ae Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 01 2017 03:35:14 +0000 Subject: import alsa-lib-1.1.3-3.el7 --- diff --git a/.alsa-lib.metadata b/.alsa-lib.metadata index de4b8b4..0e23661 100644 --- a/.alsa-lib.metadata +++ b/.alsa-lib.metadata @@ -1 +1 @@ -09f7e9b2d88287e04a4bb0d56e0cbc9018e524ec SOURCES/alsa-lib-1.1.1.tar.bz2 +8ef0b9725296ac8f24e06f20196f5b2b62ab27a9 SOURCES/alsa-lib-1.1.3.tar.bz2 diff --git a/.gitignore b/.gitignore index 07630c5..93e2d4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/alsa-lib-1.1.1.tar.bz2 +SOURCES/alsa-lib-1.1.3.tar.bz2 diff --git a/SOURCES/alsa-lib-1.0.16-no-dox-date.patch b/SOURCES/alsa-lib-1.0.16-no-dox-date.patch deleted file mode 100644 index 2669115..0000000 --- a/SOURCES/alsa-lib-1.0.16-no-dox-date.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- alsa-lib-1.0.16/doc/no_date_footer.html 1969-12-31 16:00:00.000000000 -0800 -+++ alsa-lib-1.0.16-dox/doc/no_date_footer.html 2008-04-03 17:52:52.000000000 -0700 -@@ -0,0 +1,6 @@ -+
-+Generated for $projectname by doxygen -+$doxygenversion
-+ -+ ---- alsa-lib-1.0.16/doc/doxygen.cfg.in 2008-02-05 01:23:44.000000000 -0800 -+++ alsa-lib-1.0.16-dox/doc/doxygen.cfg.in 2008-04-03 17:58:01.000000000 -0700 -@@ -117,3 +117,5 @@ - - #INPUT_FILTER = inputfilter - #FILTER_SOURCE_FILES = YES -+ -+HTML_FOOTER = no_date_footer.html diff --git a/SOURCES/alsa-lib-1.1.1-post.patch b/SOURCES/alsa-lib-1.1.1-post.patch deleted file mode 100644 index 0227a2d..0000000 --- a/SOURCES/alsa-lib-1.1.1-post.patch +++ /dev/null @@ -1,6314 +0,0 @@ -From 7c424edd116e76eee6218a1e9a6ff6c4daaf2a4d Mon Sep 17 00:00:00 2001 -From: Shengjiu Wang -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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" - * }; - * -- * 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. -+ * -+ *
Vendor Tokens
-+ * 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. -+ * -+ *
-+ * SectionVendorTokens."id of the vendor tokens" {
-+ *	comment "optional comments"
-+ *	VENDOR_TOKEN_ID1 "1"
-+ *	VENDOR_TOKEN_ID2 "2"
-+ *	VENDOR_TOKEN_ID3 "3"
-+ *	...
-+ * }
-+ * 
-+ * -+ *
Vendor Tuples
-+ * 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. -+ * -+ *
-+ * 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"
-+ *		...
-+ *	}
-+ * }
-+ * 
- * - *
Mixer Controls
- * 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. - * -+ *
Widget Private Data
-+ * Widget can have private data. For the format of the private data, please -+ * refer to section Control Private Data. -+ * - *

PCM Capabilities

- * 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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='' " -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 -Reviewed-by: Vinod Koul -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Subhransu S. Prusty -Signed-off-by: Vinod Koul -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Vinod Koul -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Vinod Koul -Signed-off-by: Takashi Iwai ---- - 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 -+* -+*/ -+#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 -+ * -+ */ -+#include "pvt.c" -+#include "stdio.h" -+#include "fcntl.h" -+#include -+#include -+#include -+#include -+#include "global.h" -+#include "list.h" -+ -+#include -+#include -+ -+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 -+#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 -+ * Nilofer, Samreen -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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 -+/* -+ * 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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?= -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 -Signed-off-by: Jörg Krause -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 ---- - 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 -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 -Signed-off-by: Takashi Iwai ---- - 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 -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 ---- - 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 -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 ---- - 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 -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 ---- - 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 -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 ---- - 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 -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 ---- - 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 - -+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 - diff --git a/SOURCES/alsa-lib-1.1.3-post.patch b/SOURCES/alsa-lib-1.1.3-post.patch new file mode 100644 index 0000000..d0f5fc8 --- /dev/null +++ b/SOURCES/alsa-lib-1.1.3-post.patch @@ -0,0 +1,3874 @@ +From 6ad2a9763d9aaab30c0470d039877b1bb61dda3b Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Tue, 27 Dec 2016 18:08:58 +0800 +Subject: [PATCH 01/37] ucm: Add ATTRIBUTE_UNUSED for unused parameters of + execute_component_seq() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To fix the following warnings: + +main.c: In function ‘execute_component_seq’: +main.c:489:24: warning: unused parameter ‘value_list1’ [-Wunused-parameter] + struct list_head *value_list1, + ^ +main.c:490:24: warning: unused parameter ‘value_list2’ [-Wunused-parameter] + struct list_head *value_list2, + ^ +main.c:491:24: warning: unused parameter ‘value_list3’ [-Wunused-parameter] + struct list_head *value_list3, + ^ + +Signed-off-by: Mengdong Lin +Signed-off-by: Takashi Iwai +--- + src/ucm/main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/ucm/main.c b/src/ucm/main.c +index 750e65d..38a5e81 100644 +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -486,9 +486,9 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, + */ + static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, + struct component_sequence *cmpt_seq, +- struct list_head *value_list1, +- struct list_head *value_list2, +- struct list_head *value_list3, ++ struct list_head *value_list1 ATTRIBUTE_UNUSED, ++ struct list_head *value_list2 ATTRIBUTE_UNUSED, ++ struct list_head *value_list3 ATTRIBUTE_UNUSED, + char *cdev) + { + struct use_case_device *device = cmpt_seq->device; +-- +2.9.3 + + +From 9ed4075f05a4242f32331f7f2c365767970f5003 Mon Sep 17 00:00:00 2001 +From: Gustavo Zacarias +Date: Wed, 21 Dec 2016 19:46:34 -0300 +Subject: [PATCH 02/37] ucm: parser needs limits.h + +It's using PATH_MAX which is defined there, otherwise the build fails on +musl libc. + +Signed-off-by: Gustavo Zacarias +Signed-off-by: Takashi Iwai +--- + src/ucm/parser.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index c98373a..f520abc 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -32,6 +32,7 @@ + + #include "ucm_local.h" + #include ++#include + + /** The name of the environment variable containing the UCM directory */ + #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" +-- +2.9.3 + + +From 0a61c796810fcec8b386e5311e871b1744b45a67 Mon Sep 17 00:00:00 2001 +From: Joshua Frkuska +Date: Fri, 30 Dec 2016 11:56:15 +0530 +Subject: [PATCH 03/37] pcm: direct: allow users to configure different period + sizes + +This patch allows the effective period size to be a multiple of the +slave-pcm period size. +Allowing only exact multiple of original period size is achieved by +borrowing code from the kernel hwrules implementation. + +This patch is intended to save cpu workload when for example, the +slave operates with very small periods but a user does not need that +small periods. + +This feature is enabled by default and can be disabled by adding +config option 'var_periodsize 0'. + +Signed-off-by: Alexander Jahn +Signed-off-by: Andreas Pape +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++------ + src/pcm/pcm_direct.h | 3 ++ + src/pcm/pcm_dmix.c | 1 + + src/pcm/pcm_dshare.c | 1 + + src/pcm/pcm_dsnoop.c | 1 + + 5 files changed, 84 insertions(+), 10 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 6434983..f5d922f 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -660,6 +660,29 @@ static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params, + return hw_param_interval_refine_one(params, var, &t); + } + ++/* this code is used 'as-is' from the alsa kernel code */ ++static int snd_interval_step(struct snd_interval *i, unsigned int min, ++ unsigned int step) ++{ ++ unsigned int n; ++ int changed = 0; ++ n = (i->min - min) % step; ++ if (n != 0 || i->openmin) { ++ i->min += step - n; ++ changed = 1; ++ } ++ n = (i->max - min) % step; ++ if (n != 0 || i->openmax) { ++ i->max -= n; ++ changed = 1; ++ } ++ if (snd_interval_checkempty(i)) { ++ i->empty = 1; ++ return -EINVAL; ++ } ++ return changed; ++} ++ + #undef REFINE_DEBUG + + int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) +@@ -710,15 +733,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + &dshare->shmptr->hw.rate); + if (err < 0) + return err; +- err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, +- &dshare->shmptr->hw.period_size); +- if (err < 0) +- return err; +- err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, +- &dshare->shmptr->hw.period_time); +- if (err < 0) +- return err; ++ + if (dshare->max_periods < 0) { ++ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, ++ &dshare->shmptr->hw.period_size); ++ if (err < 0) ++ return err; ++ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, ++ &dshare->shmptr->hw.period_time); ++ if (err < 0) ++ return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + &dshare->shmptr->hw.buffer_size); + if (err < 0) +@@ -730,11 +754,38 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + } else if (params->rmask & ((1<shmptr->hw.period_size; ++ snd_interval_t period_time = dshare->shmptr->hw.period_time; + int changed; + unsigned int max_periods = dshare->max_periods; + if (max_periods < 2) + max_periods = dshare->slave_buffer_size / dshare->slave_period_size; ++ ++ /* make sure buffer size does not exceed slave buffer size */ ++ err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE, ++ 2 * dshare->slave_period_size, dshare->slave_buffer_size); ++ if (err < 0) ++ return err; ++ if (dshare->var_periodsize) { ++ /* more tolerant settings... */ ++ if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max) ++ period_size.max = dshare->shmptr->hw.buffer_size.max / 2; ++ if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max) ++ period_time.max = dshare->shmptr->hw.buffer_time.max / 2; ++ } ++ ++ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, ++ &period_size); ++ if (err < 0) ++ return err; ++ err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, ++ &period_time); ++ if (err < 0) ++ return err; + do { + changed = 0; + err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS, +@@ -746,8 +797,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + if (err < 0) + return err; + changed |= err; ++ err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), ++ 0, dshare->slave_period_size); ++ if (err < 0) ++ return err; ++ changed |= err; ++ if (err) ++ params->rmask |= (1 << SND_PCM_HW_PARAM_PERIOD_SIZE); + } while (changed); + } ++ dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max / dshare->slave_period_size; + params->info = dshare->shmptr->s.info; + #ifdef REFINE_DEBUG + snd_output_puts(log, "DMIX REFINE (end):\n"); +@@ -1183,6 +1242,7 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) + + dmix->tread = 1; + dmix->timer_need_poll = 0; ++ dmix->timer_ticks = 1; + ret = snd_pcm_info(dmix->spcm, &info); + if (ret < 0) { + SNDERR("unable to info for slave pcm"); +@@ -1366,7 +1426,7 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) + snd_timer_params_set_auto_start(¶ms, 1); + if (dmix->type != SND_PCM_TYPE_DSNOOP) + snd_timer_params_set_early_event(¶ms, 1); +- snd_timer_params_set_ticks(¶ms, 1); ++ snd_timer_params_set_ticks(¶ms, dmix->timer_ticks); + if (dmix->tread) { + filter = (1<timer_events; +@@ -1656,6 +1716,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + rec->ipc_gid = -1; + rec->slowptr = 1; + rec->max_periods = 0; ++ rec->var_periodsize = 1; + + /* read defaults */ + if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { +@@ -1762,6 +1823,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + rec->max_periods = val; + continue; + } ++ if (strcmp(id, "var_periodsize") == 0) { ++ err = snd_config_get_bool(n); ++ if (err < 0) ++ return err; ++ rec->var_periodsize = err; ++ continue; ++ } + SNDERR("Unknown field %s", id); + return -EINVAL; + } +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index 611ad29..91e816c 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -147,12 +147,14 @@ struct snd_pcm_direct { + int tread: 1; + int timer_need_poll: 1; + unsigned int timer_events; ++ unsigned int timer_ticks; + int server_fd; + pid_t server_pid; + snd_timer_t *timer; /* timer used as poll_fd */ + int interleaved; /* we have interleaved buffer */ + int slowptr; /* use slow but more precise ptr updates */ + int max_periods; /* max periods (-1 = fixed periods, 0 = max buffer size) */ ++ int var_periodsize; /* allow variable period size if max_periods is != -1*/ + unsigned int channels; /* client's channels */ + unsigned int *bindings; + union { +@@ -326,6 +328,7 @@ struct snd_pcm_direct_open_conf { + int ipc_gid; + int slowptr; + int max_periods; ++ int var_periodsize; + snd_config_t *slave; + snd_config_t *bindings; + }; +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 825677f..0ab7323 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -1040,6 +1040,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + dmix->state = SND_PCM_STATE_OPEN; + dmix->slowptr = opts->slowptr; + dmix->max_periods = opts->max_periods; ++ dmix->var_periodsize = opts->var_periodsize; + dmix->sync_ptr = snd_pcm_dmix_sync_ptr; + + retry: +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index 29cd6c6..a1fed5d 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -725,6 +725,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, + dshare->state = SND_PCM_STATE_OPEN; + dshare->slowptr = opts->slowptr; + dshare->max_periods = opts->max_periods; ++ dshare->var_periodsize = opts->var_periodsize; + dshare->sync_ptr = snd_pcm_dshare_sync_ptr; + + retry: +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 1aedf3c..85f0ff4 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -606,6 +606,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, + dsnoop->state = SND_PCM_STATE_OPEN; + dsnoop->slowptr = opts->slowptr; + dsnoop->max_periods = opts->max_periods; ++ dsnoop->var_periodsize = opts->var_periodsize; + dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; + + retry: +-- +2.9.3 + + +From 8eeee1ab7d7db3110b7b3bb31cfb989304dced94 Mon Sep 17 00:00:00 2001 +From: Alexander Jahn +Date: Fri, 30 Dec 2016 11:59:11 +0530 +Subject: [PATCH 04/37] pcm: dshare: enable silence + +This issue depends on system load - if the process using dshare is +scheduled fast enough, then there is no noise. A delay of e.g >~2ms +produces hearable noise. + +Reproduction with instrumented aplay(sleep every 100th period for a +given time): +During the sleep time of 2000000us (2s) the hardware plays old samples +in a loop before xrun is detected and recovered after the sleep. +This is resolved by placing it in silence, in case of dshare plugin. + +Signed-off-by: Alexander Jahn +Signed-off-by: Andreas Pape +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index f5d922f..0770abc 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -1161,7 +1161,8 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str + return ret; + } + +- if (dmix->type != SND_PCM_TYPE_DMIX) ++ if (dmix->type != SND_PCM_TYPE_DMIX && ++ dmix->type != SND_PCM_TYPE_DSHARE) + goto __skip_silencing; + + ret = snd_pcm_sw_params_set_silence_threshold(spcm, &sw_params, 0); +-- +2.9.3 + + +From 7570e5d77514d8d8af387da04a010fa2ccaf543c Mon Sep 17 00:00:00 2001 +From: "mahendran.k" +Date: Fri, 30 Dec 2016 11:59:27 +0530 +Subject: [PATCH 05/37] pcm: rate: fix the hw_ptr update until the boundary + available + +For long time test case, the slave_hw_ptr will exceed the boundary +and wraparound the slave_hw_ptr. This slave boundary wraparound will +cause the rate->hw_ptr to wraparound irrespective of the +rate->boundary availability and due to that the available size goes +wrong. + +Hence, to get the correct available size, +- Its necessary to increment the rate->hw_ptr upto the rate->boundary +and then wraparound the rate->hw_ptr. +- While handling fraction part of slave period, rounded value will be +introduced by input_frames(). To eliminate rounding issue on +rate->hw_ptr, subtract last rounded value from rate->hw_ptr and add +new rounded value of present slave_hw_ptr fraction part to +rate->hw_ptr. + +Signed-off-by: mahendran.k +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_rate.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 1f830dd..61cf979 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -50,7 +50,7 @@ typedef struct _snd_pcm_rate snd_pcm_rate_t; + + struct _snd_pcm_rate { + snd_pcm_generic_t gen; +- snd_pcm_uframes_t appl_ptr, hw_ptr; ++ snd_pcm_uframes_t appl_ptr, hw_ptr, last_slave_hw_ptr; + snd_pcm_uframes_t last_commit_ptr; + snd_pcm_uframes_t orig_avail_min; + snd_pcm_sw_params_t sw_params; +@@ -563,14 +563,31 @@ static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t sl + { + snd_pcm_rate_t *rate = pcm->private_data; + ++ snd_pcm_sframes_t slave_hw_ptr_diff = slave_hw_ptr - rate->last_slave_hw_ptr; ++ snd_pcm_sframes_t last_slave_hw_ptr_frac; ++ + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + return; +- /* FIXME: boundary overlap of slave hw_ptr isn't evaluated here! +- * e.g. if slave rate is small... ++ ++ if (slave_hw_ptr_diff < 0) ++ slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */ ++ else if (slave_hw_ptr_diff == 0) ++ return; ++ last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size; ++ /* While handling fraction part fo slave period, rounded value will be ++ * introduced by input_frames(). ++ * To eliminate rounding issue on rate->hw_ptr, subtract last rounded ++ * value from rate->hw_ptr and add new rounded value of present ++ * slave_hw_ptr fraction part to rate->hw_ptr. Hence, ++ * rate->hw_ptr += [ (no. of updated slave periods * pcm rate period size) - ++ * fractional part of last_slave_hw_ptr rounded value + ++ * fractional part of updated slave hw ptr's rounded value ] + */ +- rate->hw_ptr = +- (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size + +- rate->ops.input_frames(rate->obj, slave_hw_ptr % rate->gen.slave->period_size); ++ rate->hw_ptr += ( ++ (((last_slave_hw_ptr_frac + slave_hw_ptr_diff) / rate->gen.slave->period_size) * pcm->period_size) - ++ rate->ops.input_frames(rate->obj, last_slave_hw_ptr_frac) + ++ rate->ops.input_frames(rate->obj, (last_slave_hw_ptr_frac + slave_hw_ptr_diff) % rate->gen.slave->period_size)); ++ rate->last_slave_hw_ptr = slave_hw_ptr; + + rate->hw_ptr %= pcm->boundary; + } +@@ -635,6 +652,7 @@ static int snd_pcm_rate_prepare(snd_pcm_t *pcm) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; ++ rate->last_slave_hw_ptr = 0; + err = snd_pcm_rate_init(pcm); + if (err < 0) + return err; +@@ -650,6 +668,7 @@ static int snd_pcm_rate_reset(snd_pcm_t *pcm) + return err; + *pcm->hw.ptr = 0; + *pcm->appl.ptr = 0; ++ rate->last_slave_hw_ptr = 0; + err = snd_pcm_rate_init(pcm); + if (err < 0) + return err; +-- +2.9.3 + + +From 88e4ae27bb4e47029ed57cc8e02fb1ddf2157fd9 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Mon, 19 Dec 2016 12:37:50 +0900 +Subject: [PATCH 06/37] plugin: dynamically update avail_min on slave + +mmapped capture access on some plugins can fetch data from +slave in the 'background'. A subsequent snd_pcm_wait waits +for too long time to reach avail_min threshold again. +Waiting too long leads to xruns on other devices waiting for +the capture data. +As a fix the avail_min on slave is recalculated dynamically. + +V2: updated patch to fix within 80 characters per line + +Signed-off-by: Andreas Pape +Signed-off-by: Jiada Wang +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_plugin.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index e53c5bb..5b65ac3 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -535,6 +535,68 @@ static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + return 0; + } + ++static int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, ++ snd_pcm_uframes_t avail) ++{ ++ if (pcm->stream == SND_PCM_STREAM_CAPTURE && ++ pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && ++ pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { ++ /* mmap access on capture device already consumes data from ++ * slave in avail_update operation. Entering snd_pcm_wait after ++ * having already consumed some fragments leads to waiting for ++ * too long time, as slave will unnecessarily wait for avail_min ++ * condition reached again. To avoid unnecessary wait times we ++ * adapt the avail_min threshold on slave dynamically. Just ++ * modifying slave->avail_min as a shortcut and lightweight ++ * solution does not work for all slave plugin types and in ++ * addition it will not propagate the change through all ++ * downstream plugins, so we have to use the sw_params API. ++ * note: reading fragmental parts from slave will only happen ++ * in case ++ * a) the slave can provide contineous hw_ptr between periods ++ * b) avail_min does not match one slave_period ++ */ ++ snd_pcm_plugin_t *plugin = pcm->private_data; ++ snd_pcm_t *slave = plugin->gen.slave; ++ snd_pcm_uframes_t needed_slave_avail_min; ++ snd_pcm_sframes_t available; ++ ++ /* update, as it might have changed. This will also call ++ * avail_update on slave and also can return error ++ */ ++ available = snd_pcm_avail_update(pcm); ++ if (available < 0) ++ return 0; ++ ++ if (available >= pcm->avail_min) ++ /* don't wait at all. As we can't configure avail_min ++ * of slave to 0 return here ++ */ ++ return 0; ++ ++ needed_slave_avail_min = pcm->avail_min - available; ++ if (slave->avail_min != needed_slave_avail_min) { ++ snd_pcm_sw_params_t *swparams; ++ snd_pcm_sw_params_alloca(&swparams); ++ /* pray that changing sw_params while running is ++ * properly implemented in all downstream plugins... ++ * it's legal but not commonly used. ++ */ ++ snd_pcm_sw_params_current(slave, swparams); ++ /* snd_pcm_sw_params_set_avail_min() restricts setting ++ * to >= period size. This conflicts at least with our ++ * dshare patch which allows combining multiple periods ++ * or with slaves which return hw postions between ++ * periods -> set directly in sw_param structure ++ */ ++ swparams->avail_min = needed_slave_avail_min; ++ snd_pcm_sw_params(slave, swparams); ++ } ++ avail = available; ++ } ++ return snd_pcm_generic_may_wait_for_avail_min(pcm, avail); ++} ++ + const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { + .status = snd_pcm_plugin_status, + .state = snd_pcm_generic_state, +@@ -564,7 +626,7 @@ const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_generic_poll_revents, +- .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, ++ .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, + }; + + #endif +-- +2.9.3 + + +From ff1f669df4b05da3c44dc4a79ce00233fe9de9b7 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Mon, 19 Dec 2016 12:37:51 +0900 +Subject: [PATCH 07/37] rate: dynamic update avail_min on slave + +Signed-off-by: Andreas Pape +Signed-off-by: Jiada Wang +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_plugin.c | 4 ++-- + src/pcm/pcm_plugin.h | 3 +++ + src/pcm/pcm_rate.c | 2 +- + 3 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index 5b65ac3..ad4a102 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -535,8 +535,8 @@ static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + return 0; + } + +-static int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, +- snd_pcm_uframes_t avail) ++int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, ++ snd_pcm_uframes_t avail) + { + if (pcm->stream == SND_PCM_STREAM_CAPTURE && + pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && +diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h +index 217f075..95aacb3 100644 +--- a/src/pcm/pcm_plugin.h ++++ b/src/pcm/pcm_plugin.h +@@ -50,6 +50,8 @@ typedef struct { + /* make local functions really local */ + #define snd_pcm_plugin_init \ + snd1_pcm_plugin_init ++#define snd_pcm_plugin_may_wait_for_avail_min \ ++ snd1_pcm_plugin_may_wait_for_avail_min + #define snd_pcm_plugin_fast_ops \ + snd1_pcm_plugin_fast_ops + #define snd_pcm_plugin_undo_read_generic \ +@@ -64,6 +66,7 @@ typedef struct { + void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin); + snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); + snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); ++int snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail); + + extern const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops; + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 61cf979..cbb7618 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1213,7 +1213,7 @@ static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = { + .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, + .poll_descriptors = snd_pcm_generic_poll_descriptors, + .poll_revents = snd_pcm_rate_poll_revents, +- .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, ++ .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, + }; + + static const snd_pcm_ops_t snd_pcm_rate_ops = { +-- +2.9.3 + + +From 6f7eaf92e7de73eb32bd97bad83a14fcb0f408f7 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Wed, 30 Nov 2016 00:44:32 +0900 +Subject: [PATCH 08/37] topology: fix unused-const-variable warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Last year, unused static const variable was added, then compiler generates +a below warning. + +dapm.c:43:30: warning: ‘widget_control_map’ defined but not used [-Wunused-const-variable=] + static const struct map_elem widget_control_map[] = { + ^~~~~~~~~~~~~~~~~~ + +This commit removes it. + +Fixes: 01a0e1a1c219 ("topology: Add DAPM object parser") +Signed-off-by: Takashi Sakamoto +Acked-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/dapm.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index e830751..8c585a7 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -39,14 +39,6 @@ static const struct map_elem widget_map[] = { + {"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK}, + }; + +-/* mapping of widget kcontrol text names to types */ +-static const struct map_elem widget_control_map[] = { +- {"volsw", SND_SOC_TPLG_DAPM_CTL_VOLSW}, +- {"enum_double", SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE}, +- {"enum_virt", SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT}, +- {"enum_value", SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE}, +-}; +- + static int lookup_widget(const char *w) + { + unsigned int i; +-- +2.9.3 + + +From 1eddf1f918845d1e6cbcac5516319b20cad80f2f Mon Sep 17 00:00:00 2001 +From: Adam Goode +Date: Tue, 3 Jan 2017 08:33:42 -0500 +Subject: [PATCH 09/37] seq: improve documentation about new get pid/card + functions + +Document the technique for determining if the running kernel supports +the new snd_seq_client_info_get_pid and snd_seq_client_info_get_card +functions. Also add a little information about how to use these +functions and add some cross references. + +Signed-off-by: Adam Goode +Signed-off-by: Takashi Iwai +--- + src/seq/seq.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 42 insertions(+), 2 deletions(-) + +diff --git a/src/seq/seq.c b/src/seq/seq.c +index 9279830..b206e2f 100644 +--- a/src/seq/seq.c ++++ b/src/seq/seq.c +@@ -1530,7 +1530,25 @@ int snd_seq_client_info_get_error_bounce(const snd_seq_client_info_t *info) + * \param info client_info container + * \return card number or -1 if value is not available. + * +- * Only available for SND_SEQ_KERNEL_CLIENT clients. ++ * Only available for #SND_SEQ_KERNEL_CLIENT clients. ++ * ++ * The card number can be used to query state about the hardware ++ * device providing this client, by concatenating "hw:CARD=" ++ * with the card number and using it as the name parameter ++ * to #snd_ctl_open(). ++ * ++ * \note ++ * The return value of -1 is returned for two different conditions: when the ++ * running kernel does not support this operation, and when the client ++ * does not have a hardware card attached. See ++ * #snd_seq_client_info_get_pid() for a way to determine if the ++ * currently running kernel has support for this operation. ++ * ++ * \sa snd_seq_client_info_get_pid(), ++ * snd_card_get_name(), ++ * snd_card_get_longname(), ++ * snd_ctl_open(), ++ * snd_ctl_card_info() + */ + int snd_seq_client_info_get_card(const snd_seq_client_info_t *info) + { +@@ -1543,7 +1561,29 @@ int snd_seq_client_info_get_card(const snd_seq_client_info_t *info) + * \param info client_info container + * \return pid or -1 if value is not available. + * +- * Only available for SND_SEQ_USER_CLIENT clients. ++ * Only available for #SND_SEQ_USER_CLIENT clients. ++ * ++ * \note ++ * The functionality for getting a client's PID and getting a ++ * client's card was added to the kernel at the same time, so you can ++ * use this function to determine if the running kernel ++ * supports reporting these values. If your own client has a valid ++ * PID as reported by this function, then the running kernel supports ++ * both #snd_seq_client_info_get_card() and #snd_seq_client_info_get_pid(). ++ * ++ * \note ++ * Example code for determining kernel support: ++ * \code ++ * int is_get_card_or_pid_supported(snd_seq_t *seq) ++ * { ++ * snd_seq_client_info_t *my_client_info; ++ * snd_seq_client_info_alloca(&my_client_info); ++ * snd_seq_get_client_info(seq, my_client_info); ++ * return snd_seq_client_info_get_pid(my_client_info) != -1; ++ * } ++ * \endcode ++ * ++ * \sa snd_seq_client_info_get_card() + */ + int snd_seq_client_info_get_pid(const snd_seq_client_info_t *info) + { +-- +2.9.3 + + +From 3f0dc404f16af58d20b4489b0daafcf87555dfb7 Mon Sep 17 00:00:00 2001 +From: Mounesh Sutar +Date: Tue, 10 Jan 2017 12:03:17 +0530 +Subject: [PATCH 10/37] pcm: direct: returning semop error code for semaphore + up/down failures + +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index 91e816c..aee38c5 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -263,7 +263,10 @@ static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_ + { + struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } }; + int err = semop(dmix->semid, op, 2); +- if (err == 0) dmix->locked[sem_num]++; ++ if (err == 0) ++ dmix->locked[sem_num]++; ++ else if (err == -1) ++ err = -errno; + return err; + } + +@@ -271,7 +274,10 @@ static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_nu + { + struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT }; + int err = semop(dmix->semid, &op, 1); +- if (err == 0) dmix->locked[sem_num]--; ++ if (err == 0) ++ dmix->locked[sem_num]--; ++ else if (err == -1) ++ err = -errno; + return err; + } + +-- +2.9.3 + + +From 1a9bd0f0448106b917ae7f7bedccfcbf6ce84802 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:03:36 +0530 +Subject: [PATCH 11/37] pcm: direct: Fix for sync issue on xrun recover + +If using very short periods, DSHARE/DSNOOP/DMIX may report underruns while in +status 'prepared'. This prohibits correct recovery. Now slave xrun conditions +for DSHARE/DSNOOP/DMIX are being handled properly. + +Signed-off-by: Andreas Pape +Signed-off-by: Joshua Frkuska +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ + src/pcm/pcm_direct.h | 5 ++- + src/pcm/pcm_dmix.c | 27 +++++++++++--- + src/pcm/pcm_dshare.c | 29 +++++++++++---- + src/pcm/pcm_dsnoop.c | 15 +++++++- + 5 files changed, 162 insertions(+), 16 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 0770abc..a512dd2 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -550,6 +550,101 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) + return 0; + } + ++/* ++ * Recover slave on XRUN. ++ * Even if direct plugins disable xrun detection, there might be an xrun ++ * raised directly by some drivers. ++ * The first client recovers slave pcm. ++ * Each client needs to execute sw xrun handling afterwards ++ */ ++int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct) ++{ ++ int ret; ++ int semerr; ++ ++ semerr = snd_pcm_direct_semaphore_down(direct, ++ DIRECT_IPC_SEM_CLIENT); ++ if (semerr < 0) { ++ SNDERR("SEMDOWN FAILED with err %d", semerr); ++ return semerr; ++ } ++ ++ if (snd_pcm_state(direct->spcm) != SND_PCM_STATE_XRUN) { ++ /* ignore... someone else already did recovery */ ++ semerr = snd_pcm_direct_semaphore_up(direct, ++ DIRECT_IPC_SEM_CLIENT); ++ if (semerr < 0) { ++ SNDERR("SEMUP FAILED with err %d", semerr); ++ return semerr; ++ } ++ return 0; ++ } ++ ++ ret = snd_pcm_prepare(direct->spcm); ++ if (ret < 0) { ++ SNDERR("recover: unable to prepare slave"); ++ semerr = snd_pcm_direct_semaphore_up(direct, ++ DIRECT_IPC_SEM_CLIENT); ++ if (semerr < 0) { ++ SNDERR("SEMUP FAILED with err %d", semerr); ++ return semerr; ++ } ++ return ret; ++ } ++ ++ if (direct->type == SND_PCM_TYPE_DSHARE) { ++ const snd_pcm_channel_area_t *dst_areas; ++ dst_areas = snd_pcm_mmap_areas(direct->spcm); ++ snd_pcm_areas_silence(dst_areas, 0, direct->spcm->channels, ++ direct->spcm->buffer_size, ++ direct->spcm->format); ++ } ++ ++ ret = snd_pcm_start(direct->spcm); ++ if (ret < 0) { ++ SNDERR("recover: unable to start slave"); ++ semerr = snd_pcm_direct_semaphore_up(direct, ++ DIRECT_IPC_SEM_CLIENT); ++ if (semerr < 0) { ++ SNDERR("SEMUP FAILED with err %d", semerr); ++ return semerr; ++ } ++ return ret; ++ } ++ direct->shmptr->recoveries++; ++ semerr = snd_pcm_direct_semaphore_up(direct, ++ DIRECT_IPC_SEM_CLIENT); ++ if (semerr < 0) { ++ SNDERR("SEMUP FAILED with err %d", semerr); ++ return semerr; ++ } ++ return 0; ++} ++ ++/* ++ * enter xrun state, if slave xrun occurred ++ * @return: 0 - no xrun >0: xrun happened ++ */ ++int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm) ++{ ++ if (direct->shmptr->recoveries != direct->recoveries) { ++ /* no matter how many xruns we missed - ++ * so don't increment but just update to actual counter ++ */ ++ direct->recoveries = direct->shmptr->recoveries; ++ pcm->fast_ops->drop(pcm); ++ /* trigger_tstamp update is missing in drop callbacks */ ++ gettimestamp(&direct->trigger_tstamp, pcm->tstamp_type); ++ /* no timer clear: ++ * if slave already entered xrun again the event is lost. ++ * snd_pcm_direct_clear_timer_queue(direct); ++ */ ++ direct->state = SND_PCM_STATE_XRUN; ++ return 1; ++ } ++ return 0; ++} ++ + int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) + { + snd_pcm_direct_t *dmix = pcm->private_data; +@@ -572,6 +667,12 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in + } + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_XRUN: ++ /* recover slave and update client state to xrun ++ * before returning POLLERR ++ */ ++ snd_pcm_direct_slave_recover(dmix); ++ snd_pcm_direct_client_chk_xrun(dmix, pcm); ++ /* fallthrough */ + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_SETUP: + events |= POLLERR; +@@ -1382,6 +1483,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = dmix->shmptr->s.period_size; + dmix->slave_boundary = spcm->boundary; ++ dmix->recoveries = dmix->shmptr->recoveries; + + ret = snd_pcm_mmap(spcm); + if (ret < 0) { +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index aee38c5..d48f6b4 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -66,6 +66,7 @@ typedef struct { + char socket_name[256]; /* name of communication socket */ + snd_pcm_type_t type; /* PCM type (currently only hw) */ + int use_server; ++ unsigned int recoveries; /* no of executed recoveries on slave*/ + struct { + unsigned int format; + snd_interval_t rate; +@@ -157,6 +158,7 @@ struct snd_pcm_direct { + int var_periodsize; /* allow variable period size if max_periods is != -1*/ + unsigned int channels; /* client's channels */ + unsigned int *bindings; ++ unsigned int recoveries; /* mirror of executed recoveries on slave */ + union { + struct { + int shmid_sum; /* IPC global sum ring buffer memory identification */ +@@ -324,7 +326,8 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm + snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm); + snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm); + int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); +- ++int snd_pcm_direct_slave_recover(snd_pcm_direct_t *direct); ++int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm); + int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); + struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 0ab7323..f72ee67 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -434,15 +434,21 @@ static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr + static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dmix = pcm->private_data; ++ int err; + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dmix->state = SND_PCM_STATE_DISCONNECTED; + return -ENODEV; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) ++ return err; ++ break; + default: + break; + } +- ++ if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) ++ return -EPIPE; + if (dmix->slowptr) + snd_pcm_hwsync(dmix->spcm); + +@@ -828,12 +834,16 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_XRUN: +- return -EPIPE; ++ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) ++ return err; ++ break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } ++ if (snd_pcm_direct_client_chk_xrun(dmix, pcm)) ++ return -EPIPE; + if (! size) + return 0; + snd_pcm_mmap_appl_forward(pcm, size); +@@ -841,8 +851,10 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, + if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) + return err; + } else if (dmix->state == SND_PCM_STATE_RUNNING || +- dmix->state == SND_PCM_STATE_DRAINING) +- snd_pcm_dmix_sync_ptr(pcm); ++ dmix->state == SND_PCM_STATE_DRAINING) { ++ if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) ++ return err; ++ } + if (dmix->state == SND_PCM_STATE_RUNNING || + dmix->state == SND_PCM_STATE_DRAINING) { + /* ok, we commit the changes after the validation of area */ +@@ -858,10 +870,13 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, + static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dmix = pcm->private_data; ++ int err; + + if (dmix->state == SND_PCM_STATE_RUNNING || +- dmix->state == SND_PCM_STATE_DRAINING) +- snd_pcm_dmix_sync_ptr(pcm); ++ dmix->state == SND_PCM_STATE_DRAINING) { ++ if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) ++ return err; ++ } + return snd_pcm_mmap_playback_avail(pcm); + } + +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index a1fed5d..0d80037 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -162,7 +162,7 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p + snd_pcm_direct_t *dshare = pcm->private_data; + snd_pcm_uframes_t old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; +- ++ + old_slave_hw_ptr = dshare->slave_hw_ptr; + dshare->slave_hw_ptr = slave_hw_ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; +@@ -202,15 +202,21 @@ static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_p + static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dshare = pcm->private_data; ++ int err; + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dshare->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) ++ return err; ++ break; + default: + break; + } +- ++ if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) ++ return -EPIPE; + if (dshare->slowptr) + snd_pcm_hwsync(dshare->spcm); + +@@ -516,12 +522,16 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_XRUN: +- return -EPIPE; ++ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) ++ return err; ++ break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } ++ if (snd_pcm_direct_client_chk_xrun(dshare, pcm)) ++ return -EPIPE; + if (! size) + return 0; + snd_pcm_mmap_appl_forward(pcm, size); +@@ -529,8 +539,10 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, + if ((err = snd_pcm_dshare_start_timer(dshare)) < 0) + return err; + } else if (dshare->state == SND_PCM_STATE_RUNNING || +- dshare->state == SND_PCM_STATE_DRAINING) +- snd_pcm_dshare_sync_ptr(pcm); ++ dshare->state == SND_PCM_STATE_DRAINING) { ++ if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) ++ return err; ++ } + if (dshare->state == SND_PCM_STATE_RUNNING || + dshare->state == SND_PCM_STATE_DRAINING) { + /* ok, we commit the changes after the validation of area */ +@@ -546,10 +558,13 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, + static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dshare = pcm->private_data; ++ int err; + + if (dshare->state == SND_PCM_STATE_RUNNING || +- dshare->state == SND_PCM_STATE_DRAINING) +- snd_pcm_dshare_sync_ptr(pcm); ++ dshare->state == SND_PCM_STATE_DRAINING) { ++ if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) ++ return err; ++ } + return snd_pcm_mmap_playback_avail(pcm); + } + +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 85f0ff4..618d469 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -132,14 +132,21 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) + snd_pcm_direct_t *dsnoop = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; +- ++ int err; ++ + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED; + return -ENODEV; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) ++ return err; ++ break; + default: + break; + } ++ if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) ++ return -EPIPE; + if (dsnoop->slowptr) + snd_pcm_hwsync(dsnoop->spcm); + old_slave_hw_ptr = dsnoop->slave_hw_ptr; +@@ -410,12 +417,16 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm, + + switch (snd_pcm_state(dsnoop->spcm)) { + case SND_PCM_STATE_XRUN: +- return -EPIPE; ++ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) ++ return err; ++ break; + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } ++ if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm)) ++ return -EPIPE; + if (dsnoop->state == SND_PCM_STATE_RUNNING) { + err = snd_pcm_dsnoop_sync_ptr(pcm); + if (err < 0) +-- +2.9.3 + + +From 789ee39727a12d6573b4d79e9cd7a375e6b8b005 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:03:54 +0530 +Subject: [PATCH 12/37] pcm: direct: check state before enter poll on timer + +To avoid the chances of timeout, we need to check the enter poll +in state xrun. + +Signed-off-by: Andreas Pape +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 40 ++++++++++++++++++++++++++++++++++++++++ + src/pcm/pcm_direct.h | 2 ++ + src/pcm/pcm_dmix.c | 9 +++++++-- + src/pcm/pcm_dshare.c | 9 +++++++-- + src/pcm/pcm_dsnoop.c | 9 +++++++-- + 5 files changed, 63 insertions(+), 6 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index a512dd2..f4d7c3f 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -645,6 +645,46 @@ int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm) + return 0; + } + ++/* ++ * This is the only operation guaranteed to be called before entering poll(). ++ * Direct plugins use fd of snd_timer to poll on, these timers do NOT check ++ * state of substream in kernel by intention. ++ * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP). ++ * If xrun event was not correctly handled or was ignored it will never be ++ * evaluated again afterwards. ++ * This will result in snd_pcm_wait() always returning timeout. ++ * In contrast poll() on pcm hardware checks ALSA state and will immediately ++ * return POLLERR on XRUN. ++ * ++ * To prevent timeout and applications endlessly spinning without xrun ++ * detected we add a state check here which may trigger the xrun sequence. ++ * ++ * return count of filled descriptors or negative error code ++ */ ++int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, ++ unsigned int space) ++{ ++ if (pcm->poll_fd < 0) { ++ SNDMSG("poll_fd < 0"); ++ return -EIO; ++ } ++ if (space >= 1 && pfds) { ++ pfds->fd = pcm->poll_fd; ++ pfds->events = pcm->poll_events | POLLERR | POLLNVAL; ++ } else { ++ return 0; ++ } ++ ++ /* this will also evaluate slave state and enter xrun if necessary */ ++ switch (snd_pcm_state(pcm)) { ++ case SND_PCM_STATE_XRUN: ++ return -EPIPE; ++ default: ++ break; ++ } ++ return 1; ++} ++ + int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) + { + snd_pcm_direct_t *dmix = pcm->private_data; +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index d48f6b4..66107ec 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -307,6 +307,8 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, + snd_config_t *cfg); + int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock); + int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid); ++int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, ++ unsigned int space); + int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); + int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info); + int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index f72ee67..6664210 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -462,17 +462,22 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) + static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dmix = pcm->private_data; ++ int err; + snd_pcm_state_t state; + state = snd_pcm_state(dmix->spcm); + switch (state) { +- case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dmix->state = state; + return state; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dmix)) < 0) ++ return err; ++ break; + default: + break; + } ++ snd_pcm_direct_client_chk_xrun(dmix, pcm); + if (dmix->state == STATE_RUN_PENDING) + return SNDRV_PCM_STATE_RUNNING; + return dmix->state; +@@ -968,7 +973,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { + .avail_update = snd_pcm_dmix_avail_update, + .mmap_commit = snd_pcm_dmix_mmap_commit, + .htimestamp = snd_pcm_dmix_htimestamp, +- .poll_descriptors = NULL, ++ .poll_descriptors = snd_pcm_direct_poll_descriptors, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_dmix_poll_revents, + }; +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index 0d80037..fdc95e3 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -255,17 +255,22 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dshare = pcm->private_data; ++ int err; + snd_pcm_state_t state; + state = snd_pcm_state(dshare->spcm); + switch (state) { +- case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dshare->state = state; + return state; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dshare)) < 0) ++ return err; ++ break; + default: + break; + } ++ snd_pcm_direct_client_chk_xrun(dshare, pcm); + if (dshare->state == STATE_RUN_PENDING) + return SNDRV_PCM_STATE_RUNNING; + return dshare->state; +@@ -646,7 +651,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { + .avail_update = snd_pcm_dshare_avail_update, + .mmap_commit = snd_pcm_dshare_mmap_commit, + .htimestamp = snd_pcm_dshare_htimestamp, +- .poll_descriptors = NULL, ++ .poll_descriptors = snd_pcm_direct_poll_descriptors, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_direct_poll_revents, + }; +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 618d469..a148771 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -208,17 +208,22 @@ static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm) + { + snd_pcm_direct_t *dsnoop = pcm->private_data; ++ int err; + snd_pcm_state_t state; + state = snd_pcm_state(dsnoop->spcm); + switch (state) { +- case SND_PCM_STATE_XRUN: + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_DISCONNECTED: + dsnoop->state = state; + return state; ++ case SND_PCM_STATE_XRUN: ++ if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0) ++ return err; ++ break; + default: + break; + } ++ snd_pcm_direct_client_chk_xrun(dsnoop, pcm); + return dsnoop->state; + } + +@@ -531,7 +536,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { + .avail_update = snd_pcm_dsnoop_avail_update, + .mmap_commit = snd_pcm_dsnoop_mmap_commit, + .htimestamp = snd_pcm_dsnoop_htimestamp, +- .poll_descriptors = NULL, ++ .poll_descriptors = snd_pcm_direct_poll_descriptors, + .poll_descriptors_count = NULL, + .poll_revents = snd_pcm_direct_poll_revents, + }; +-- +2.9.3 + + +From 79a358ae26f74ed9b92b2190d4725325edf0c787 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Tue, 10 Jan 2017 12:04:09 +0530 +Subject: [PATCH 13/37] pcm: direct: don't return bogus buffer levels in xrun + state + +Signed-off-by: Andreas Pape +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dmix.c | 3 +++ + src/pcm/pcm_dshare.c | 3 +++ + src/pcm/pcm_dsnoop.c | 3 +++ + 3 files changed, 9 insertions(+) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 6664210..2ef6159 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -882,6 +882,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) + if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) + return err; + } ++ if (dmix->state == SND_PCM_STATE_XRUN) ++ return -EPIPE; ++ + return snd_pcm_mmap_playback_avail(pcm); + } + +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index fdc95e3..331f799 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -570,6 +570,9 @@ static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) + if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) + return err; + } ++ if (dshare->state == SND_PCM_STATE_XRUN) ++ return -EPIPE; ++ + return snd_pcm_mmap_playback_avail(pcm); + } + +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index a148771..539b671 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -454,6 +454,9 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm) + if (err < 0) + return err; + } ++ if (dsnoop->state == SND_PCM_STATE_XRUN) ++ return -EPIPE; ++ + return snd_pcm_mmap_capture_avail(pcm); + } + +-- +2.9.3 + + +From 360c976aaa051809c34cb412ffa52380baeaabee Mon Sep 17 00:00:00 2001 +From: Vinod Koul +Date: Thu, 12 Jan 2017 14:50:28 +0530 +Subject: [PATCH 14/37] conf/ucm: broxton: add broxton-rt298 conf files + +This adds the UCM conf files for broxton enabling with rt298 codec on +I2S audio, HDMI and DMIC ports. + +Signed-off-by: Nishit Sharma +Signed-off-by: G Kranthi +Signed-off-by: Vinod Koul +Signed-off-by: Takashi Iwai +--- + configure.ac | 1 + + src/conf/ucm/Makefile.am | 2 +- + src/conf/ucm/broxton-rt298/Hdmi1 | 22 +++++ + src/conf/ucm/broxton-rt298/Hdmi2 | 14 +++ + src/conf/ucm/broxton-rt298/HiFi | 129 ++++++++++++++++++++++++++ + src/conf/ucm/broxton-rt298/Makefile.am | 4 + + src/conf/ucm/broxton-rt298/broxton-rt298.conf | 58 ++++++++++++ + 7 files changed, 229 insertions(+), 1 deletion(-) + create mode 100644 src/conf/ucm/broxton-rt298/Hdmi1 + create mode 100644 src/conf/ucm/broxton-rt298/Hdmi2 + create mode 100644 src/conf/ucm/broxton-rt298/HiFi + create mode 100644 src/conf/ucm/broxton-rt298/Makefile.am + create mode 100644 src/conf/ucm/broxton-rt298/broxton-rt298.conf + +diff --git a/configure.ac b/configure.ac +index 71bd852..d645ab6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -684,6 +684,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \ + src/conf/topology/bxtrt298/Makefile \ + alsalisp/Makefile aserver/Makefile \ + test/Makefile test/lsb/Makefile \ ++ src/conf/ucm/broxton-rt298/Makefile \ + utils/Makefile utils/alsa-lib.spec utils/alsa.pc) + + dnl Create asoundlib.h dynamically according to configure options +diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am +index a11d324..ea9b385 100644 +--- a/src/conf/ucm/Makefile.am ++++ b/src/conf/ucm/Makefile.am +@@ -1 +1 @@ +-SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 skylake-rt286 VEYRON-I2S chtrt5645 DB410c ++SUBDIRS=DAISY-I2S PandaBoard PandaBoardES SDP4430 tegraalc5632 PAZ00 GoogleNyan broadwell-rt286 skylake-rt286 VEYRON-I2S chtrt5645 DB410c broxton-rt298 +diff --git a/src/conf/ucm/broxton-rt298/Hdmi1 b/src/conf/ucm/broxton-rt298/Hdmi1 +new file mode 100644 +index 0000000..48514f4 +--- /dev/null ++++ b/src/conf/ucm/broxton-rt298/Hdmi1 +@@ -0,0 +1,22 @@ ++# Usecase for device HDMI1/Display Port stereo playback on Intel SKYLAKE/KABYLAKE platforms ++# For Audio in I2S mode ++ ++SectionDevice."Hdmi1" { ++ Comment "HDMI/Display Port 1 Stereo" ++ ++ EnableSequence [ ++ exec "echo Hdmi1 EnableSequnece" ++ ] ++ ++ DisableSequence [ ++ exec "echo Hdmi1 DisableSequnece" ++ ] ++ ++ Value { ++ PlaybackPCM "hw:broxtonrt298,4" ++ PlaybackChannels "2" ++ PlaybackPriority "3" ++ JackControl "HDMI/DP, pcm=4 Jack" ++ } ++} ++ +diff --git a/src/conf/ucm/broxton-rt298/Hdmi2 b/src/conf/ucm/broxton-rt298/Hdmi2 +new file mode 100644 +index 0000000..764f8b9 +--- /dev/null ++++ b/src/conf/ucm/broxton-rt298/Hdmi2 +@@ -0,0 +1,14 @@ ++# Usecase for device HDMI2/Display Port stereo playback on Intel Broxton platforms ++# For Audio in I2S mode ++ ++SectionDevice."Hdmi2" { ++ Comment "HDMI/Display Port 2 Stereo" ++ ++ Value { ++ PlaybackPCM "hw:broxtonrt298,5" ++ PlaybackChannels "2" ++ PlaybackPriority "4" ++ JackControl "HDMI/DP, pcm=5 Jack" ++ } ++} ++ +diff --git a/src/conf/ucm/broxton-rt298/HiFi b/src/conf/ucm/broxton-rt298/HiFi +new file mode 100644 +index 0000000..2e2d6fe +--- /dev/null ++++ b/src/conf/ucm/broxton-rt298/HiFi +@@ -0,0 +1,129 @@ ++# Usecase for stereo playback Speaker and Headset, Recording on DMIC and Headset MIC. ++# For Audio in I2S mode on Intel Broxton platforms ++ ++SectionVerb { ++ ++ EnableSequence [ ++ cdev "hw:broxtonrt298" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:broxtonrt298" ++ ] ++ ++ Value { ++ TQ "HiFi" ++ CapturePCM "hw:broxtonrt298,1" ++ PlaybackPCM "hw:broxtonrt298,0" ++ } ++} ++ ++SectionDevice."dmiccap" { ++ Comment "DMIC Stereo" ++ ++ ConflictingDevice [ ++ "Headset" ++ ] ++ ++ EnableSequence [ ++ ++ cdev "hw:broxtonrt298" ++ exec "echo broxtonrt298 dmiccap called" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo codec0_in mi Switch' 0" ++ cset "name='Mic Jack Switch' 0" ++ ++ ] ++ ++ DisableSequence [ ++ cdev "hw:broxtonrt298" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='ADC 0 Mux' 0" ++ ] ++ Value { ++ CaptureChannels "2" ++ CapturePriority "2" ++ } ++} ++ ++SectionDevice."Headphones" { ++ Comment "Headphones" ++ ++ ConflictingDevice [ ++ "Speaker" ++ ] ++ EnableSequence [ ++ cdev "hw:broxtonrt298" ++ exec "echo broxtonrt298 Headphone called" ++ cset "name='HPO L Switch' 1" ++ cset "name='HPO R Switch' 1" ++ cset "name='Headphone Jack Switch' 1" ++ cset "name='Speaker Playback Switch' 0,0" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:broxtonrt298" ++ ] ++ Value { ++ PlaybackChannels "2" ++ PlaybackPriority "1" ++ JackControl "Headphone Jack" ++ JackHWMute "Speaker" ++ } ++} ++ ++SectionDevice."Speaker" { ++ Comment "Speaker" ++ ++ ConflictingDevice [ ++ "Headphones" ++ ] ++ EnableSequence [ ++ cdev "hw:broxtonrt298" ++ exec "echo broxtonrt298 speaker called" ++ cset "name='SPO Switch' 1" ++ cset "name='Speaker Playback Switch' 1,1" ++ cset "name='Speaker Switch' 1" ++ cset "name='HPO L Switch' 0" ++ cset "name='HPO R Switch' 0" ++ ] ++ ++ DisableSequence [ ++ ] ++ Value { ++ PlaybackChannels "2" ++ PlaybackPriority "1" ++ JackHWMute "Headphones" ++ } ++} ++ ++SectionDevice."Headset" { ++ Comment "Headset Mic" ++ ++ ConflictingDevice [ ++ "dmiccap" ++ ] ++ EnableSequence [ ++ cdev "hw:broxtonrt298" ++ exec "echo broxtonrt298 Headset called" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='ADC0 Capture Volume' 105,105" ++ cset "name='ADC 0 Mux' 0" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 0" ++ ] ++ ++ DisableSequence [ ++ cdev "hw:broxtonrt298" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo codec0_in mi Switch' 0" ++ ] ++ Value { ++ CaptureChannels "2" ++ CapturePriority "2" ++ JackControl "Mic Jack" ++ } ++} +diff --git a/src/conf/ucm/broxton-rt298/Makefile.am b/src/conf/ucm/broxton-rt298/Makefile.am +new file mode 100644 +index 0000000..80f480e +--- /dev/null ++++ b/src/conf/ucm/broxton-rt298/Makefile.am +@@ -0,0 +1,4 @@ ++alsaconfigdir = @ALSA_CONFIG_DIR@ ++ucmdir = $(alsaconfigdir)/ucm/broxton-rt298 ++ucm_DATA = broxton-rt298.conf HiFi Hdmi1 Hdmi2 ++EXTRA_DIST = $(ucm_DATA) +diff --git a/src/conf/ucm/broxton-rt298/broxton-rt298.conf b/src/conf/ucm/broxton-rt298/broxton-rt298.conf +new file mode 100644 +index 0000000..3f3d0be +--- /dev/null ++++ b/src/conf/ucm/broxton-rt298/broxton-rt298.conf +@@ -0,0 +1,58 @@ ++# UCM for Intel Broxton platforms ++# For Audio in I2S mode ++ ++SectionUseCase."HiFi" { ++ File "HiFi" ++ Comment "Play and record HiFi quality Music" ++} ++ ++SectionUseCase."Hdmi1" { ++ File "Hdmi1" ++ Comment "Play on Hdmi/DP 1" ++} ++ ++SectionUseCase."Hdmi2" { ++ File "Hdmi2" ++ Comment "Play on Hdmi/DP 2" ++} ++ ++ValueDefaults { ++ PlaybackCTL "hw:broxtonrt298" ++ CaptureCTL "hw:broxtonrt298" ++ CaptureChannels "2" ++ CapturePriority "2" ++} ++ ++SectionDefaults [ ++ cdev "hw:broxtonrt298" ++ exec "echo broxtonrt298 CONF Defaults" ++ cset "name='Headphone Jack Switch' 1" ++ cset "name='Speaker Switch' 1" ++ cset "name='Speaker Playback Switch' 0,0" ++ cset "name='Front DAC Switch' 1" ++ cset "name='Front RECMIX Switch' 0" ++ cset "name='Mic Jack Switch' 1" ++ cset "name='ADC 0 Mux' 2" ++ cset "name='ADC 1 Mux' 0" ++ cset "name='DAC0 Playback Volume' 100,100" ++ cset "name='HPO L Switch' 0" ++ cset "name='HPO Mux' 0" ++ cset "name='HPO R Switch' 0" ++ cset "name='Pin 5 Mux' 1" ++ cset "name='Pin 6 Mux' 2" ++ cset "name='Pin 7 Mux' 3" ++ cset "name='RECMIX Beep Switch' 0" ++ cset "name='RECMIX Line1 Switch' 0" ++ cset "name='RECMIX Mic1 Switch' 0" ++ cset "name='SPK Mux' 0" ++ cset "name='SPO Switch' 1" ++ cset "name='codec0_out mo codec0_in mi Switch' 0" ++ cset "name='codec0_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='codec0_out mo media0_in mi Switch' 1" ++ cset "name='codec1_out mo codec0_in mi Switch' 0" ++ cset "name='codec1_out mo dmic01_hifi_in mi Switch' 0" ++ cset "name='codec1_out mo media0_in mi Switch' 0" ++ cset "name='media0_out mo codec0_in mi Switch' 1" ++ cset "name='media0_out mo dmic01_hifi_in mi Switch' 1" ++ cset "name='media0_out mo media0_in mi Switch' 0" ++] +-- +2.9.3 + + +From 24e63b75275e9c923c336b8dba3919b980e8f234 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 16 Jan 2017 16:21:52 +0100 +Subject: [PATCH 15/37] pcm: direct: Fix deadlock in poll_descriptors + +The recent change in PCM direct plugins to check XRUN in +poll_descriptors callback caused a regression; as consequence, the +whole playback hangs up. + +The culprit is a mutex dead lock by the call in snd_pcm_state() inside +the new snd_pcm_direct_poll_descriptors(). The poll_descriptors code +path is protected with pcm mutex, thus an unlocked version +(__snd_pcm_state()) has to be used inside the callback instead. + +Fixes: 789ee39727a1 ("pcm: direct: check state before enter poll on timer") +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index f4d7c3f..e4bef78 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -676,7 +676,8 @@ int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, + } + + /* this will also evaluate slave state and enter xrun if necessary */ +- switch (snd_pcm_state(pcm)) { ++ /* using __snd_pcm_state() since this function is called inside lock */ ++ switch (__snd_pcm_state(pcm)) { + case SND_PCM_STATE_XRUN: + return -EPIPE; + default: +-- +2.9.3 + + +From 2b9b3f013467765219c8ab8a50943d3c7db68f75 Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:52:35 +0800 +Subject: [PATCH 16/37] ucm: Assure the user input card name not to exceed max + size of card long name + +Users can load a card's UCM configuration file by giving the card short +name or long name, which should not exceed the maximum card long name +defined by the kernel. The kernel uses an 80-character buffer to store +the card long name. + +Signed-off-by: Mengdong Lin +Signed-off-by: Takashi Iwai +--- + src/ucm/parser.c | 6 ++++++ + src/ucm/ucm_local.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index f520abc..f61201a 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -1335,6 +1335,12 @@ static int load_master_config(const char *card_name, snd_config_t **cfg) + char *env = getenv(ALSA_CONFIG_UCM_VAR); + int err; + ++ if (strnlen(card_name, MAX_CARD_LONG_NAME) == MAX_CARD_LONG_NAME) { ++ uc_error("error: invalid card name %s (at most %d chars)\n", ++ card_name, MAX_CARD_LONG_NAME - 1); ++ return -EINVAL; ++ } ++ + snprintf(filename, sizeof(filename)-1, + "%s/%s/%s.conf", env ? env : ALSA_USE_CASE_DIR, + card_name, card_name); +diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h +index 6d3302f..e41aafa 100644 +--- a/src/ucm/ucm_local.h ++++ b/src/ucm/ucm_local.h +@@ -41,6 +41,7 @@ + #include "use-case.h" + + #define MAX_FILE 256 ++#define MAX_CARD_LONG_NAME 80 + #define ALSA_USE_CASE_DIR ALSA_CONFIG_DIR "/ucm" + + #define SEQUENCE_ELEMENT_TYPE_CDEV 1 +-- +2.9.3 + + +From 4b9297e65f541f1a6c1b4a036f66936b9cafe030 Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:53:35 +0800 +Subject: [PATCH 17/37] ucm: Load device-specific configuration file based on + the card long name + +Intel DSP platform drivers are used by many different devices. For user +space to differentiate them, ASoC machine drivers may use the DMI info +(vendor-product-version-board) as card long name. Possible card long names +are: +DellInc.-XPS139343-01-0310JH +ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA +Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX +... + +If we want to define a device-specific UCM config file for a card, we +need to use the card long name as the name of both the directory that +contains the UCM config file and the UCM config file itself, like +longname/longname.conf + +When being asked to load configuration file of a card, UCM will try to +find the card in the local machine and get its long name. If the card +long name is available, try to load the file longname/longname.conf to +get the best device-specific configuration; if this file is not available, +fall back to load the default configuration file shortname/shortname.conf +as before. + +This update is backward compatible, because if ASoC machine drivers don't +explicity use DMI or other means to set the card long name, ASoC core +will use the card short name as the long name. And so UCM will load the +config file that matches both the card short name and the long name. + +Signed-off-by: Mengdong Lin +Signed-off-by: Takashi Iwai +--- + src/ucm/parser.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + src/ucm/ucm_local.h | 2 ++ + 2 files changed, 97 insertions(+), 4 deletions(-) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index f61201a..798bf48 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -56,6 +56,9 @@ static const char * const component_dir[] = { + NULL, /* terminator */ + }; + ++static int filename_filter(const struct dirent *dirent); ++static int is_component_directory(const char *dir); ++ + static int parse_sequence(snd_use_case_mgr_t *uc_mgr, + struct list_head *base, + snd_config_t *cfg); +@@ -1329,6 +1332,66 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) + return 0; + } + ++/* find the card in the local machine and store the card long name */ ++static int get_card_long_name(snd_use_case_mgr_t *mgr) ++{ ++ const char *card_name = mgr->card_name; ++ snd_ctl_t *handle; ++ int card, err; ++ snd_ctl_card_info_t *info; ++ const char *_name, *_long_name; ++ ++ snd_ctl_card_info_alloca(&info); ++ ++ card = -1; ++ if (snd_card_next(&card) < 0 || card < 0) { ++ uc_error("no soundcards found..."); ++ return -1; ++ } ++ ++ while (card >= 0) { ++ char name[32]; ++ ++ sprintf(name, "hw:%d", card); ++ err = snd_ctl_open(&handle, name, 0); ++ if (err < 0) { ++ uc_error("control open (%i): %s", card, ++ snd_strerror(err)); ++ goto next_card; ++ } ++ ++ err = snd_ctl_card_info(handle, info); ++ if (err < 0) { ++ uc_error("control hardware info (%i): %s", card, ++ snd_strerror(err)); ++ snd_ctl_close(handle); ++ goto next_card; ++ } ++ ++ /* Find the local card by comparing the given name with the ++ * card short name and long name. The given card name may be ++ * either a short name or long name, because users may open ++ * the card by either of the two names. ++ */ ++ _name = snd_ctl_card_info_get_name(info); ++ _long_name = snd_ctl_card_info_get_longname(info); ++ if (!strcmp(card_name, _name) ++ || !strcmp(card_name, _long_name)) { ++ strcpy(mgr->card_long_name, _long_name); ++ snd_ctl_close(handle); ++ return 0; ++ } ++ ++ snd_ctl_close(handle); ++next_card: ++ if (snd_card_next(&card) < 0) { ++ uc_error("snd_card_next"); ++ break; ++ } ++ } ++ ++ return -1; ++} + static int load_master_config(const char *card_name, snd_config_t **cfg) + { + char filename[MAX_FILE]; +@@ -1356,15 +1419,43 @@ static int load_master_config(const char *card_name, snd_config_t **cfg) + return 0; + } + +-/* load master use case file for sound card */ ++/* load master use case file for sound card ++ * ++ * The same ASoC machine driver can be shared by many different devices. ++ * For user space to differentiate them and get the best device-specific ++ * configuration, ASoC machine drivers may use the DMI info ++ * (vendor-product-version-board) as the card long name. And user space can ++ * define configuration files like longnamei/longname.conf for a specific device. ++ * ++ * This function will try to find the card in the local machine and get its ++ * long name, then load the file longname/longname.conf to get the best ++ * device-specific configuration. If the card is not found in the local ++ * machine or the device-specific file is not available, fall back to load ++ * the default configuration file name/name.conf. ++ */ + int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) + { + snd_config_t *cfg; + int err; + +- err = load_master_config(uc_mgr->card_name, &cfg); +- if (err < 0) +- return err; ++ err = get_card_long_name(uc_mgr); ++ if (err == 0) /* load file that maches the card long name */ ++ err = load_master_config(uc_mgr->card_long_name, &cfg); ++ ++ if (err == 0) { ++ /* got device-specific file that matches the card long name */ ++ strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name); ++ } else { ++ /* Fall back to the file that maches the given card name, ++ * either short name or long name (users may open a card by ++ * its name or long name). ++ */ ++ err = load_master_config(uc_mgr->card_name, &cfg); ++ if (err < 0) ++ return err; ++ strcpy(uc_mgr->conf_file_name, uc_mgr->card_name); ++ } ++ + err = parse_master_file(uc_mgr, cfg); + snd_config_delete(cfg); + if (err < 0) +diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h +index e41aafa..299a5b9 100644 +--- a/src/ucm/ucm_local.h ++++ b/src/ucm/ucm_local.h +@@ -191,6 +191,8 @@ struct use_case_verb { + */ + struct snd_use_case_mgr { + char *card_name; ++ char card_long_name[MAX_CARD_LONG_NAME]; ++ char conf_file_name[MAX_CARD_LONG_NAME]; + char *comment; + + /* use case verb, devices and modifier configs parsed from files */ +-- +2.9.3 + + +From e93d93a8cd37f94f119aba72ca05d7f92b648bcc Mon Sep 17 00:00:00 2001 +From: Mengdong Lin +Date: Wed, 18 Jan 2017 11:53:42 +0800 +Subject: [PATCH 18/37] ucm: Add command 'get _file' to get the config file + name of the opened card + +After opening a card, this command can show the name of the actually +loaded configuration file, either matches the card name or card long name. +So developers can check if there is a device-sepcific configuration file +available for a given card. + +Signed-off-by: Mengdong Lin +Signed-off-by: Takashi Iwai +--- + include/use-case.h | 1 + + src/ucm/main.c | 14 ++++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/include/use-case.h b/include/use-case.h +index 8911645..ae22bde 100644 +--- a/include/use-case.h ++++ b/include/use-case.h +@@ -230,6 +230,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, + * Known identifiers: + * - NULL - return current card + * - _verb - return current verb ++ * - _file - return configuration file loaded for current card + * + * - [=]{NAME}[/[{modifier}|{/device}][/{verb}]] + * - value identifier {NAME} +diff --git a/src/ucm/main.c b/src/ucm/main.c +index 38a5e81..2d33886 100644 +--- a/src/ucm/main.c ++++ b/src/ucm/main.c +@@ -1528,6 +1528,20 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, + goto __end; + } + err = 0; ++ } else if (strcmp(identifier, "_file") == 0) { ++ /* get the conf file name of the opened card */ ++ if ((uc_mgr->card_name == NULL) ++ || (uc_mgr->conf_file_name[0] == '\0')) { ++ err = -ENOENT; ++ goto __end; ++ } ++ *value = strndup(uc_mgr->conf_file_name, MAX_FILE); ++ if (*value == NULL) { ++ err = -ENOMEM; ++ goto __end; ++ } ++ err = 0; ++ + } else if (identifier[0] == '_') { + err = -ENOENT; + goto __end; +-- +2.9.3 + + +From ec40aafa4374f2388876702513c4b3eee2e2235f Mon Sep 17 00:00:00 2001 +From: Liam Girdwood +Date: Tue, 24 Jan 2017 14:59:08 +0000 +Subject: [PATCH 19/37] topology: Fix incorrect license in source comments. + +The topology source files had the wrong licence specified in the +comments when initially upstreamed. The topology source files are all +licensed under the LGPL-2.1 and not the GPLv2. + +All earlier versions of the alsa-lib topology source files must be +considered LGPL-2.1 like the other source files in alsa-lib and also +as specified in the alsa-lib COPYING file. + +Signed-off-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + src/topology/builder.c | 17 +++++++++-------- + src/topology/channel.c | 17 +++++++++-------- + src/topology/ctl.c | 17 +++++++++-------- + src/topology/dapm.c | 17 +++++++++-------- + src/topology/data.c | 17 +++++++++-------- + src/topology/elem.c | 17 +++++++++-------- + src/topology/ops.c | 17 +++++++++-------- + src/topology/parser.c | 17 +++++++++-------- + src/topology/pcm.c | 17 +++++++++-------- + src/topology/text.c | 17 +++++++++-------- + 10 files changed, 90 insertions(+), 80 deletions(-) + +diff --git a/src/topology/builder.c b/src/topology/builder.c +index 20fa925..dcd9e2a 100644 +--- a/src/topology/builder.c ++++ b/src/topology/builder.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/channel.c b/src/topology/channel.c +index c2f1fea..8516b23 100644 +--- a/src/topology/channel.c ++++ b/src/topology/channel.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 907a97f..1da3d18 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 8c585a7..eef72bb 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/data.c b/src/topology/data.c +index 0d5c430..e2aa38c 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/elem.c b/src/topology/elem.c +index db26483..efcf3e9 100644 +--- a/src/topology/elem.c ++++ b/src/topology/elem.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/ops.c b/src/topology/ops.c +index 1b5c1e2..6f8dc1f 100644 +--- a/src/topology/ops.c ++++ b/src/topology/ops.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/parser.c b/src/topology/parser.c +index c5f9757..cfc20e0 100644 +--- a/src/topology/parser.c ++++ b/src/topology/parser.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 8f8a703..5568d57 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +diff --git a/src/topology/text.c b/src/topology/text.c +index 303fbeb..cba6887 100644 +--- a/src/topology/text.c ++++ b/src/topology/text.c +@@ -2,14 +2,15 @@ + Copyright(c) 2014-2015 Intel Corporation + All rights reserved. + +- This program is free software; you can redistribute it and/or modify +- it under the terms of version 2 of the GNU General Public License as +- published by the Free Software Foundation. +- +- This program is distributed in the hope that it will be useful, but +- WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- General Public License for more details. ++ This library is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of ++ the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. + + Authors: Mengdong Lin + Yao Jin +-- +2.9.3 + + +From 4dfa8f08fb834f7b087f35f9ba1746cd0c989d02 Mon Sep 17 00:00:00 2001 +From: Manohar Narkhede +Date: Wed, 25 Jan 2017 22:14:15 +0100 +Subject: [PATCH 20/37] conf/cards: add support for pistachio-card. + +The data sheet of the chip and technical reference manual can be found at https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.pdf +and https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf. + +The additional information about the cards can be found in src/conf/cards/pistachio-card.conf file. + +Signed-off-by: Manohar Narkhede +Signed-off-by: Takashi Iwai +--- + src/conf/cards/Makefile.am | 1 + + src/conf/cards/aliases.conf | 1 + + src/conf/cards/pistachio-card.conf | 58 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 60 insertions(+) + create mode 100644 src/conf/cards/pistachio-card.conf + +diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am +index 008d399..60b5309 100644 +--- a/src/conf/cards/Makefile.am ++++ b/src/conf/cards/Makefile.am +@@ -39,6 +39,7 @@ cfg_files = aliases.conf \ + Maestro3.conf \ + NFORCE.conf \ + PC-Speaker.conf \ ++ pistachio-card.conf \ + PMac.conf \ + PMacToonie.conf \ + PS3.conf \ +diff --git a/src/conf/cards/aliases.conf b/src/conf/cards/aliases.conf +index 4a92fb2..60f9d26 100644 +--- a/src/conf/cards/aliases.conf ++++ b/src/conf/cards/aliases.conf +@@ -55,6 +55,7 @@ AV100 cards.CMI8788 + AV200 cards.CMI8788 + CMI8786 cards.CMI8788 + CMI8787 cards.CMI8788 ++pistachio cards.pistachio-card + + + +diff --git a/src/conf/cards/pistachio-card.conf b/src/conf/cards/pistachio-card.conf +new file mode 100644 +index 0000000..59cd920 +--- /dev/null ++++ b/src/conf/cards/pistachio-card.conf +@@ -0,0 +1,58 @@ ++# ++# Configuration for the pistachio chip. ++# ++# The data sheet of the chip and technical reference manual can be ++found at ++https://docs.creatordev.io/ci40/guides/hardwaredocs/cXT200_datasheet2.p ++df # and ++https://docs.creatordev.io/ci40/guides/hardwaredocs/MIPS_Creator_cXT200_Technical_Reference_Manual_1.0.112.pdf. ++# ++# The list of hardware devices is as per below: ++# ++# root@OpenWrt:/# arecord -l ++# **** List of CAPTURE Hardware Devices **** card 0: pistachiocard [pistachio-card], device 1: pistachio-spdif-in snd-soc-dummy-dai-1 [] ++# Subdevices: 1/1 ++# Subdevice #0: subdevice #0 ++# card 0: pistachiocard [pistachio-card], device 4: pistachio-i2s-in-0 snd-soc-dummy-dai-4 [] ++# Subdevices: 1/1 ++# Subdevice #0: subdevice #0 ++# ++# root@OpenWrt:/# aplay -l ++# **** List of PLAYBACK Hardware Devices **** card 0: pistachiocard [pistachio-card], device 0: pistachio-spdif-out snd-soc-dummy-dai-0 [] ++# Subdevices: 1/1 ++# Subdevice #0: subdevice #0 ++# card 0: pistachiocard [pistachio-card], device 2: pistachio-parallel-out pistachio_internal_dac-2 [] ++# Subdevices: 1/1 ++# Subdevice #0: subdevice #0 ++# card 0: pistachiocard [pistachio-card], device 3: pistachio-i2s-out snd-soc-dummy-dai-3 [] ++# Subdevices: 1/1 ++# Subdevice #0: subdevice #0 ++# ++ ++pistachio-card.pcm.default{ ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ default "pistachio" ++ } ++ @args.DEVICE { ++ type integer ++ default 2 ++ } ++ ++ type asym ++ capture.pcm { ++ type multi ++ slaves.a.pcm "hw:0,4" ++ slaves.a.channels 12 ++ bindings.0.slave a ++ bindings.0.channel 4 ++ bindings.1.slave a ++ bindings.1.channel 5 ++ } ++ ++ playback.pcm { ++ type hw ++ card $CARD ++ device $DEVICE ++ +-- +2.9.3 + + +From e1143dd9ba350eb19d13d4e298eeb55179712a1e Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 27 Jan 2017 12:01:51 +0100 +Subject: [PATCH 21/37] pcm: multi: Drop the fixed slave_map[] in + snd_pcm_multi_open() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +slave_map[] in snd_pcm_multi_open() is a fixed size array and +obviously we have no overflow check, and eventually the program gets +an error when more than 64 channels are used. + +Although we can modify the code to allocate the array dynamically, it +turned out that we can drop the whole slave_map[] thingy in this +function when looking at the code closely. In the past, it was used +to identify the one-to-many mapping. But the check was dropped, and +now it's nothing more than a sanity check. + +Reported-by: Jörg Müller +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_multi.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c +index c4b1fba..9e4be71 100644 +--- a/src/pcm/pcm_multi.c ++++ b/src/pcm/pcm_multi.c +@@ -1015,7 +1015,6 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + snd_pcm_multi_t *multi; + unsigned int i; + snd_pcm_stream_t stream; +- char slave_map[64][64] = { { 0 } }; + int err; + + assert(pcmp); +@@ -1059,8 +1058,6 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + bind->slave_channel = schannels[i]; + if (sidxs[i] < 0) + continue; +- assert(!slave_map[sidxs[i]][schannels[i]]); +- slave_map[sidxs[i]][schannels[i]] = 1; + } + multi->channels_count = channels_count; + +-- +2.9.3 + + +From 53dc36f1f465e2a1f9ed37906a7f16a438f941e4 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 7 Feb 2017 14:25:17 +0100 +Subject: [PATCH 22/37] conf: Add card config for Intel HDMI/DP LPE audio + +It's a playback-only device with a single PCM dedicated for HDMI/DP +output. The dmix is working with the latest driver code, so enable it +for default, while providing the hdmi PCM dev for the accesses with +AES bits. + +Signed-off-by: Takashi Iwai +--- + src/conf/cards/HdmiLpeAudio.conf | 85 ++++++++++++++++++++++++++++++++++++++++ + src/conf/cards/Makefile.am | 1 + + 2 files changed, 86 insertions(+) + create mode 100644 src/conf/cards/HdmiLpeAudio.conf + +diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf +new file mode 100644 +index 0000000..f5836c0 +--- /dev/null ++++ b/src/conf/cards/HdmiLpeAudio.conf +@@ -0,0 +1,85 @@ ++# ++# Configuration for the Intel HDMI/DP LPE audio ++# ++ ++ ++ ++HdmiLpeAudio.pcm.front.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type softvol ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ control { ++ name "PCM Playback Volume" ++ card $CARD ++ } ++} ++ ++# default with dmix+softvol ++HdmiLpeAudio.pcm.default { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type softvol ++ slave.pcm { ++ @func concat ++ strings [ "dmix:" $CARD ] ++ } ++ control { ++ name "PCM Playback Volume" ++ card $CARD ++ } ++ } ++} ++ ++ ++ ++ ++ ++ ++ ++ ++ ++HdmiLpeAudio.pcm.hdmi.0 { ++ @args [ CARD AES0 AES1 AES2 AES3 ] ++ @args.CARD { ++ type string ++ } ++ @args.AES0 { ++ type integer ++ } ++ @args.AES1 { ++ type integer ++ } ++ @args.AES2 { ++ type integer ++ } ++ @args.AES3 { ++ type integer ++ } ++ type hooks ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ hooks.0 { ++ type ctl_elems ++ hook_args [ ++ { ++ interface PCM ++ name "IEC958 Playback Default" ++ lock true ++ preserve true ++ value [ $AES0 $AES1 $AES2 $AES3 ] ++ } ++ ] ++ } ++} +diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am +index 60b5309..e8b530e 100644 +--- a/src/conf/cards/Makefile.am ++++ b/src/conf/cards/Makefile.am +@@ -30,6 +30,7 @@ cfg_files = aliases.conf \ + FireWave.conf \ + GUS.conf \ + HDA-Intel.conf \ ++ HdmiLpeAudio.conf \ + ICE1712.conf \ + ICE1724.conf \ + ICH.conf \ +-- +2.9.3 + + +From b5a2c06f6c5d69fc71ef648af95a044ee1dc25d0 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 9 Feb 2017 17:23:22 +0100 +Subject: [PATCH 23/37] pcm: Avoid lock for snd_pcm_nonblock() + +snd_pcm_nonblock() is called as snd_pcm_abort(). Since +snd_pcm_abort() is called often from a signal handler to clean things +up (e.g. aplay does it), we may face a deadlock if the signal is +raised during the locked operation. + +There can be some way to check the deadlock state, but they would cost +much. Since the race condition of snd_pcm_nonblock() is quite small, +let's just drop the locking inside snd_pcm_nonblock() as a +workaround. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 0cf740f..c136d55 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -759,7 +759,10 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) + int err = 0; + + assert(pcm); +- __snd_pcm_lock(pcm); /* forced lock due to pcm field change */ ++ /* FIXME: __snd_pcm_lock() call below is commented out because of the ++ * the possible deadlock in signal handler calling snd_pcm_abort() ++ */ ++ /* __snd_pcm_lock(pcm); */ /* forced lock due to pcm field change */ + if ((err = pcm->ops->nonblock(pcm->op_arg, nonblock)) < 0) + goto unlock; + if (nonblock == 2) { +@@ -775,7 +778,7 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock) + pcm->mode &= ~SND_PCM_NONBLOCK; + } + unlock: +- __snd_pcm_unlock(pcm); ++ /* __snd_pcm_unlock(pcm); */ /* FIXME: see above */ + return err; + } + +-- +2.9.3 + + +From e31a3273df6eb619e35d10bf6a0fc0fded91d559 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 9 Feb 2017 17:29:21 +0100 +Subject: [PATCH 24/37] pcm: Disable locking in async mode + +When PCM is operated in async mode and an async handler calls some PCM +functions with lock during other PCM operations, we may hit a +deadlock. + +Although async mode is rarely used, it's still a possible use case. +Disable the locking when the stream is opened in async mode or it's +set to async mode via snd_pcm_async(). + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index c136d55..493e903 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -799,6 +799,8 @@ int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid) + sig = SIGIO; + if (pid == 0) + pid = getpid(); ++ /* async handler may lead to a deadlock; suppose no multi thread */ ++ pcm->lock_enabled = 0; + return pcm->ops->async(pcm->op_arg, sig, pid); + } + #endif +@@ -2597,7 +2599,10 @@ int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name, + * each plugin may suppress this in its open call + */ + pcm->need_lock = 1; +- { ++ if (mode & SND_PCM_ASYNC) { ++ /* async handler may lead to a deadlock; suppose no MT */ ++ pcm->lock_enabled = 0; ++ } else { + /* set lock_enabled field depending on $LIBASOUND_THREAD_SAFE */ + static int do_lock_enable = -1; /* uninitialized */ + +-- +2.9.3 + + +From 22eca6468b4aea47c783770ec0739d1e13bf3bfc Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 10 Feb 2017 12:16:12 +0100 +Subject: [PATCH 25/37] pcm: dmix: Allow disabling x86 optimizations + +The dmix plugin has some optimized implementations for x86 using the +direct memory accesses, which was rather the original version, in +addition to the "generic" implementation using the semaphore +blocking. The x86 implementation relies on the memory coherency *and* +the fast read/write on it. + +For other architectures, this has been always disabled just because of +memory coherency. But, the recent LPE audio development revealed +that, even on x86 platforms, the read/write performance might become +extremely bad when the buffer is marked as uncached. Some drivers +already know the buffer is uncached, we need to switch to the generic +mode in such a case. + +This patch introduces yet another flag to dmix configuration, +direct_memory_access, that indicates whether the x86-specific +optimization can be used or not. Each driver can set the flag in its +cards config namespace, and the default dmix config refers to it. + +As of this patch, only HDMI LPE Audio driver sets it. + +Signed-off-by: Takashi Iwai +--- + src/conf/cards/HdmiLpeAudio.conf | 3 +++ + src/conf/pcm/dmix.conf | 15 +++++++++++++++ + src/pcm/pcm_direct.c | 8 ++++++++ + src/pcm/pcm_direct.h | 2 ++ + src/pcm/pcm_dmix.c | 1 + + src/pcm/pcm_dmix_i386.c | 5 +++++ + src/pcm/pcm_dmix_x86_64.c | 5 +++++ + 7 files changed, 39 insertions(+) + +diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf +index f5836c0..61bdfea 100644 +--- a/src/conf/cards/HdmiLpeAudio.conf ++++ b/src/conf/cards/HdmiLpeAudio.conf +@@ -20,6 +20,9 @@ HdmiLpeAudio.pcm.front.0 { + } + } + ++# uncached memory reads have a high penalty ++HdmiLpeAudio.dmix.direct_memory_access false ++ + # default with dmix+softvol + HdmiLpeAudio.pcm.default { + @args [ CARD ] +diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf +index 7d0aa01..2d3b329 100644 +--- a/src/conf/pcm/dmix.conf ++++ b/src/conf/pcm/dmix.conf +@@ -49,6 +49,21 @@ pcm.!dmix { + @func refer + name defaults.pcm.ipc_perm + } ++ direct_memory_access { ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards." ++ { ++ @func card_driver ++ card $CARD ++ } ++ ".dmix.direct_memory_access" ++ ] ++ } ++ default true ++ } + slave { + pcm { + type hw +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index e4bef78..364191b 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -1861,6 +1861,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + rec->slowptr = 1; + rec->max_periods = 0; + rec->var_periodsize = 1; ++ rec->direct_memory_access = 1; + + /* read defaults */ + if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { +@@ -1974,6 +1975,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + rec->var_periodsize = err; + continue; + } ++ if (strcmp(id, "direct_memory_access") == 0) { ++ err = snd_config_get_bool(n); ++ if (err < 0) ++ return err; ++ rec->direct_memory_access = err; ++ continue; ++ } + SNDERR("Unknown field %s", id); + return -EINVAL; + } +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index 66107ec..fba55fd 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -159,6 +159,7 @@ struct snd_pcm_direct { + unsigned int channels; /* client's channels */ + unsigned int *bindings; + unsigned int recoveries; /* mirror of executed recoveries on slave */ ++ int direct_memory_access; /* use arch-optimized buffer RW */ + union { + struct { + int shmid_sum; /* IPC global sum ring buffer memory identification */ +@@ -340,6 +341,7 @@ struct snd_pcm_direct_open_conf { + int slowptr; + int max_periods; + int var_periodsize; ++ int direct_memory_access; + snd_config_t *slave; + snd_config_t *bindings; + }; +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 2ef6159..dd0356e 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -1065,6 +1065,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + dmix->max_periods = opts->max_periods; + dmix->var_periodsize = opts->var_periodsize; + dmix->sync_ptr = snd_pcm_dmix_sync_ptr; ++ dmix->direct_memory_access = opts->direct_memory_access; + + retry: + if (first_instance) { +diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c +index dcc6b9a..1ab983a 100644 +--- a/src/pcm/pcm_dmix_i386.c ++++ b/src/pcm/pcm_dmix_i386.c +@@ -87,6 +87,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) + { + static int smp = 0, mmx = 0, cmov = 0; + ++ if (!dmix->direct_memory_access) { ++ generic_mix_select_callbacks(dmix); ++ return; ++ } ++ + if (!((1ULL<< dmix->shmptr->s.format) & i386_dmix_supported_format)) { + generic_mix_select_callbacks(dmix); + return; +diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c +index 831046d..34c40d4 100644 +--- a/src/pcm/pcm_dmix_x86_64.c ++++ b/src/pcm/pcm_dmix_x86_64.c +@@ -70,6 +70,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) + { + static int smp = 0; + ++ if (!dmix->direct_memory_access) { ++ generic_mix_select_callbacks(dmix); ++ return; ++ } ++ + if (!((1ULL<< dmix->shmptr->s.format) & x86_64_dmix_supported_format)) { + generic_mix_select_callbacks(dmix); + return; +-- +2.9.3 + + +From df7694d80cdd7d273b34ead6841b9f32f5991966 Mon Sep 17 00:00:00 2001 +From: Timo Wischer +Date: Fri, 17 Feb 2017 12:45:36 +0530 +Subject: [PATCH 26/37] pcm: dmix_rewind corrupts application pointer fix + +sometimes pulseaudio stops with the following assertion in libasound.so: +alsa-lib-1.0.29/src/pcm/pcm.c:2761: +snd_pcm_area_copy: Assertion `dst < src || dst >= src + bytes' failed. +Application pointer is handled properly, in cases of rewind operations. + +Signed-off-by: Timo Wischer +Signed-off-by: Ravikiran Polepalli +Signed-off-by: Mikhail Durnev +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dmix.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index dd0356e..46142e5 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -706,7 +706,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + { + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_appl_ptr, slave_size; +- snd_pcm_uframes_t appl_ptr, size, transfer, result; ++ snd_pcm_uframes_t appl_ptr, size, transfer, result, frames_to_remix; + int err; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + +@@ -717,6 +717,13 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + return err; + } + ++ /* (appl_ptr - last_appl_ptr) indicates the frames which are not ++ * already mixed ++ * (last_appl_ptr - hw_ptr) indicates the frames which are already ++ * mixed but not played yet. ++ * So they can be remixed. ++ */ ++ + if (dmix->last_appl_ptr < dmix->appl_ptr) + size = dmix->appl_ptr - dmix->last_appl_ptr; + else +@@ -729,6 +736,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + return size; + result = size; + ++ /* Always at this point last_appl_ptr == appl_ptr ++ * So (appl_ptr - hw_ptr) indicates the frames which can be remixed ++ */ + if (dmix->hw_ptr < dmix->appl_ptr) + size = dmix->appl_ptr - dmix->hw_ptr; + else +@@ -741,9 +751,12 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr); + if (slave_size < size) + size = slave_size; +- frames -= size; +- result += size; +- ++ ++ /* frames which should be remixed will be saved ++ * to also backward the appl pointer on success ++ */ ++ frames_to_remix = size; ++ + /* add sample areas here */ + src_areas = snd_pcm_mmap_areas(pcm); + dst_areas = snd_pcm_mmap_areas(dmix->spcm); +@@ -769,15 +782,15 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + appl_ptr += transfer; + appl_ptr %= pcm->buffer_size; + } +- dmix->last_appl_ptr -= frames; +- dmix->last_appl_ptr %= pcm->boundary; +- dmix->slave_appl_ptr -= frames; +- dmix->slave_appl_ptr %= dmix->slave_boundary; + dmix_up_sem(dmix); + +- snd_pcm_mmap_appl_backward(pcm, frames); ++ snd_pcm_mmap_appl_backward(pcm, frames_to_remix); ++ result += frames_to_remix; ++ /* At this point last_appl_ptr and appl_ptr has to indicate the ++ * position of the first not mixed frame ++ */ + +- return result + frames; ++ return result; + } + + static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm) +-- +2.9.3 + + +From 9219034301a3bf3d8de57ac5672bbc1c53f18049 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Fri, 17 Feb 2017 12:45:56 +0530 +Subject: [PATCH 27/37] pcm: direct: fix race on clearing timer events + +snd_timer handling is racy: plugins clear timer queue if avail_min +is not reached to force a sleep on timer. The race can happen if +the expected event arrives in between the avail check and the +clearing of pending events. If this race happens, the user will +unnecessarily wait for one more timer event. On low latency/realtime +streams this can lead to xruns and must be avoided. + +As a fix we recheck avail after having cleared poll events. + +Signed-off-by: Andreas Pape +Signed-off-by: Jiada Wang +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.c | 23 +++++++++++++++++++---- + src/pcm/pcm_direct.h | 2 +- + 2 files changed, 20 insertions(+), 5 deletions(-) + +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 364191b..8a75c42 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -515,10 +515,12 @@ int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid) + } + + /* empty the timer read queue */ +-void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) ++int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) + { ++ int changed = 0; + if (dmix->timer_need_poll) { + while (poll(&dmix->timer_fd, 1, 0) > 0) { ++ changed++; + /* we don't need the value */ + if (dmix->tread) { + snd_timer_tread_t rbuf[4]; +@@ -533,15 +535,17 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix) + snd_timer_tread_t rbuf[4]; + int len; + while ((len = snd_timer_read(dmix->timer, rbuf, +- sizeof(rbuf))) > 0 && ++ sizeof(rbuf))) > 0 ++ && (++changed) && + len != sizeof(rbuf[0])) + ; + } else { + snd_timer_read_t rbuf; + while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0) +- ; ++ changed++; + } + } ++ return changed; + } + + int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix) +@@ -693,6 +697,8 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in + int empty = 0; + + assert(pfds && nfds == 1 && revents); ++ ++timer_changed: + events = pfds[0].revents; + if (events & POLLIN) { + snd_pcm_uframes_t avail; +@@ -720,7 +726,16 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in + break; + default: + if (empty) { +- snd_pcm_direct_clear_timer_queue(dmix); ++ /* here we have a race condition: ++ * if period event arrived after the avail_update call ++ * above we might clear this event with the following ++ * clear_timer_queue. ++ * There is no way to do this in atomic manner, so we ++ * need to recheck avail_update if we successfully ++ * cleared a poll event. ++ */ ++ if (snd_pcm_direct_clear_timer_queue(dmix)) ++ goto timer_changed; + events &= ~(POLLOUT|POLLIN); + /* additional check */ + switch (__snd_pcm_state(pcm)) { +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index fba55fd..24e85f0 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -322,7 +322,7 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm); + int snd_pcm_direct_prepare(snd_pcm_t *pcm); + int snd_pcm_direct_resume(snd_pcm_t *pcm); + int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); +-void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); ++int snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); + int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); + int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); + +-- +2.9.3 + + +From fe65b00f337dd08f8c14d54b0ce6b516424d78e8 Mon Sep 17 00:00:00 2001 +From: Timo Wischer +Date: Fri, 17 Feb 2017 12:47:17 +0530 +Subject: [PATCH 28/37] pcm: file: Enable file writing for capture path + +This commit reverts parts of commit 4081be0b87ab9fa53a8906e66bc240f18a7a9a54, +because it is realy useful to use the file plugin in a capture path for +debugging. Also it fixes the truncate issue mentioned in above commit. + +Additionally following MMAP access issue is considered: +$ arecord -D teeraw -M -d5 arecord.wav +Recording WAVE 'arecord.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono +ALSA lib pcm/pcm_file.c:358:(snd_pcm_file_write_bytes) +write failed: Bad file descriptor +ALSA lib pcm/pcm_file.c:358:(snd_pcm_file_write_bytes) +write failed: Bad file descriptor +arecord: pcm/pcm_file.c:397: snd_pcm_file_add_frames: +Assertion `file->wbuf_used_bytes < file->wbuf_size_bytes' failed. +Aborted by signal Aborted... + +Signed-off-by: Timo Wischer +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_file.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c +index 6d119d6..0363f84 100644 +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -544,6 +544,7 @@ static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pc + static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) + { + snd_pcm_file_t *file = pcm->private_data; ++ snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n; + + n = _snd_pcm_readi(file->gen.slave, buffer, size); +@@ -555,8 +556,10 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc + __snd_pcm_unlock(pcm); + if (n < 0) + return n; +- return n * 8 / pcm->frame_bits; ++ n = n * 8 / pcm->frame_bits; + } ++ snd_pcm_areas_from_buf(pcm, areas, buffer); ++ snd_pcm_file_add_frames(pcm, areas, 0, n); + return n; + } + +@@ -564,6 +567,7 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc + static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) + { + snd_pcm_file_t *file = pcm->private_data; ++ snd_pcm_channel_area_t areas[pcm->channels]; + snd_pcm_sframes_t n; + + if (file->ifd >= 0) { +@@ -572,6 +576,10 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm + } + + n = _snd_pcm_readn(file->gen.slave, bufs, size); ++ if (n > 0) { ++ snd_pcm_areas_from_bufs(pcm, areas, bufs); ++ snd_pcm_file_add_frames(pcm, areas, 0, n); ++ } + return n; + } + +@@ -635,7 +643,7 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + a->first = slave->sample_bits * channel; + a->step = slave->frame_bits; + } +- if ((file->fd < 0) && (pcm->stream == SND_PCM_STREAM_PLAYBACK)) { ++ if (file->fd < 0) { + err = snd_pcm_file_open_output_file(file); + if (err < 0) { + SYSERR("failed opening output file %s", file->fname); +-- +2.9.3 + + +From a50496346f39e91ecd42cb09bc5c95321131be55 Mon Sep 17 00:00:00 2001 +From: Andreas Pape +Date: Fri, 17 Feb 2017 12:47:36 +0530 +Subject: [PATCH 29/37] pcm: status dump fix timestamp formatting + +nanosecond part formatted with %06 will give incorrect/confusing results: + +trigger_time: 154.9748287 +trigger_time: 154.60109090 +trigger_time: 154.110425257 + +time seems to run backwards... + +This patch converts to us before printing +which gives the correct/expected result: + +trigger_time: 154.009748 +trigger_time: 154.060109 +trigger_time: 154.110425 + +Signed-off-by: Andreas Pape +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 493e903..a16fd86 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -2194,9 +2194,10 @@ int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out) + assert(status); + snd_output_printf(out, " state : %s\n", snd_pcm_state_name((snd_pcm_state_t) status->state)); + snd_output_printf(out, " trigger_time: %ld.%06ld\n", +- status->trigger_tstamp.tv_sec, status->trigger_tstamp.tv_nsec); ++ status->trigger_tstamp.tv_sec, ++ status->trigger_tstamp.tv_nsec / 1000); + snd_output_printf(out, " tstamp : %ld.%06ld\n", +- status->tstamp.tv_sec, status->tstamp.tv_nsec); ++ status->tstamp.tv_sec, status->tstamp.tv_nsec / 1000); + snd_output_printf(out, " delay : %ld\n", (long)status->delay); + snd_output_printf(out, " avail : %ld\n", (long)status->avail); + snd_output_printf(out, " avail_max : %ld\n", (long)status->avail_max); +-- +2.9.3 + + +From fbb957138135e09ed9fd0180dcad549aad815465 Mon Sep 17 00:00:00 2001 +From: Awais Belal +Date: Fri, 17 Feb 2017 12:47:49 +0530 +Subject: [PATCH 30/37] pcm: extplug: refinement of masks in extplug + +It should be possible to use empty mask format with extplug. +The refinement of mask via extplug is now modified, +to accept empty masks as well to work properly. + +Signed-off-by: Awais Belal +Signed-off-by: Mounesh Sutar +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_extplug.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c +index a04f826..1004f54 100644 +--- a/src/pcm/pcm_extplug.c ++++ b/src/pcm/pcm_extplug.c +@@ -172,6 +172,8 @@ int snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int ty + unsigned int i; + + parm += type; ++ if (!parm->active) ++ return 0; + memset(&bits, 0, sizeof(bits)); + for (i = 0; i < parm->num_list; i++) + bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); +-- +2.9.3 + + +From 97be19cf6f44fc5084828114c53281dff6e365b4 Mon Sep 17 00:00:00 2001 +From: Alan Young +Date: Thu, 7 Apr 2016 09:15:04 +0100 +Subject: [PATCH 31/37] pcm: rate: Add capability to pass configuration node to + plugins + +If a rate plugin uses a node (compound) instead of a plain string for +its "converter", and that compound is not a simple string array, then +the compound will be passed as an additional parameter to the new plugin +open() function (SND_PCM_RATE_PLUGIN_CONF_ENTRY(XXX)). The previous +open() function (SND_PCM_RATE_PLUGIN_ENTRY(XXX)) will be called if the +CONF version is not found. It is up to the plugin to determine whether +the presence of the conf parameter is mandatory. + +Signed-off-by: Alan Young +Signed-off-by: Takashi Iwai +--- + include/pcm_rate.h | 5 +++- + src/pcm/pcm_rate.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 82 insertions(+), 10 deletions(-) + +diff --git a/include/pcm_rate.h b/include/pcm_rate.h +index 4d70df2..da278ac 100644 +--- a/include/pcm_rate.h ++++ b/include/pcm_rate.h +@@ -120,11 +120,14 @@ typedef struct snd_pcm_rate_ops { + typedef int (*snd_pcm_rate_open_func_t)(unsigned int version, void **objp, + snd_pcm_rate_ops_t *opsp); + ++typedef int (*snd_pcm_rate_open_conf_func_t)(unsigned int version, void **objp, ++ snd_pcm_rate_ops_t *opsp, const snd_config_t *conf); ++ + /** + * Define the object entry for external PCM rate-converter plugins + */ + #define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open +- ++#define SND_PCM_RATE_PLUGIN_CONF_ENTRY(name) _snd_pcm_rate_##name##_open_conf + + #ifndef DOC_HIDDEN + /* old rate_ops for protocol version 0x010001 */ +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index cbb7618..46eb797 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1258,26 +1258,48 @@ static const char *const default_rate_plugins[] = { + "speexrate", "linear", NULL + }; + +-static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose) ++static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_config_t *converter_conf, int verbose) + { +- char open_name[64], lib_name[128], *lib = NULL; ++ char open_name[64], open_conf_name[64], lib_name[128], *lib = NULL; + snd_pcm_rate_open_func_t open_func; ++ snd_pcm_rate_open_conf_func_t open_conf_func; + int err; + + snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); ++ snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", type); + if (!is_builtin_plugin(type)) { + snprintf(lib_name, sizeof(lib_name), + "%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type); + lib = lib_name; + } ++ ++ rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; ++ rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; ++ rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; ++ ++ open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL); ++ if (open_conf_func) { ++ err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION, ++ &rate->obj, &rate->ops, converter_conf); ++ if (!err) { ++ rate->plugin_version = rate->ops.version; ++ if (rate->ops.get_supported_rates) ++ rate->ops.get_supported_rates(rate->obj, ++ &rate->rate_min, ++ &rate->rate_max); ++ rate->open_func = open_conf_func; ++ return 0; ++ } else { ++ snd_dlobj_cache_put(open_conf_func); ++ return err; ++ } ++ } ++ + open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose); + if (!open_func) + return -ENOENT; + + rate->open_func = open_func; +- rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; +- rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; +- rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; + + err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); + if (!err) { +@@ -1301,6 +1323,30 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose) + } + #endif + ++/* ++ * If the conf is an array of alternatives then the id of ++ * the first element will be "0" (or maybe NULL). Otherwise assume it is ++ * a structure. ++ */ ++static int is_string_array(const snd_config_t *conf) ++{ ++ snd_config_iterator_t i; ++ ++ if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) ++ return 0; ++ ++ i = snd_config_iterator_first(conf); ++ if (i && i != snd_config_iterator_end(conf)) { ++ snd_config_t *n = snd_config_iterator_entry(i); ++ const char *id; ++ snd_config_get_id(n, &id); ++ if (id && strcmp(id, "0") != 0) ++ return 0; ++ } ++ ++ return 1; ++} ++ + /** + * \brief Creates a new rate PCM + * \param pcmp Returns created PCM handle +@@ -1353,24 +1399,42 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + if (!converter) { + const char *const *types; + for (types = default_rate_plugins; *types; types++) { +- err = rate_open_func(rate, *types, 0); ++ err = rate_open_func(rate, *types, NULL, 0); + if (!err) { + type = *types; + break; + } + } + } else if (!snd_config_get_string(converter, &type)) +- err = rate_open_func(rate, type, 1); +- else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { ++ err = rate_open_func(rate, type, NULL, 1); ++ else if (is_string_array(converter)) { + snd_config_iterator_t i, next; + snd_config_for_each(i, next, converter) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_string(n, &type) < 0) + break; +- err = rate_open_func(rate, type, 0); ++ err = rate_open_func(rate, type, NULL, 0); + if (!err) + break; + } ++ } else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { ++ snd_config_iterator_t i, next; ++ snd_config_for_each(i, next, converter) { ++ snd_config_t *n = snd_config_iterator_entry(i); ++ const char *id; ++ snd_config_get_id(n, &id); ++ if (strcmp(id, "name") != 0) ++ continue; ++ snd_config_get_string(n, &type); ++ break; ++ } ++ if (!type) { ++ SNDERR("No name given for rate converter"); ++ snd_pcm_free(pcm); ++ free(rate); ++ return -EINVAL; ++ } ++ err = rate_open_func(rate, type, converter, 1); + } else { + SNDERR("Invalid type for rate converter"); + snd_pcm_free(pcm); +@@ -1439,6 +1503,11 @@ pcm.name { + converter [ STR1 STR2 ... ] # optional + # Converter type, default is taken from + # defaults.pcm.rate_converter ++ # or ++ converter { # optional ++ name STR # Convertor type ++ xxx yyy # optional convertor-specific configuration ++ } + } + \endcode + +-- +2.9.3 + + +From 3bad0a21b4d13d8d10691f382c836897fa7a7cb9 Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Wed, 22 Feb 2017 16:45:00 -0300 +Subject: [PATCH 32/37] Drop ppc64-specific workaround for versioned symbols + +Currently aserver fails to build when using parameter +--without-versioned, due to an workaround for ppc64 +(06221f86d207cb33ddd4867ca5301eeb247c4400). This workaround is +not required anymore on the ppc64 ABI v2, and, in fact is breaking the +compilation. Reverting this commit + +Signed-off-by: Breno Leitao +Signed-off-by: Takashi Iwai +--- + include/alsa-symbols.h | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/include/alsa-symbols.h b/include/alsa-symbols.h +index 51cb982..eeacfdb 100644 +--- a/include/alsa-symbols.h ++++ b/include/alsa-symbols.h +@@ -29,19 +29,10 @@ + #define INTERNAL_CONCAT2_2(Pre, Post) Pre##Post + #define INTERNAL(Name) INTERNAL_CONCAT2_2(__, Name) + +-#ifdef __powerpc64__ +-# define symbol_version(real, name, version) \ +- __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version); \ +- __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@" #version) +-# define default_symbol_version(real, name, version) \ +- __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version); \ +- __asm__ (".symver ." ASM_NAME(#real) ",." ASM_NAME(#name) "@@" #version) +-#else + # define symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@" #version) + # define default_symbol_version(real, name, version) \ + __asm__ (".symver " ASM_NAME(#real) "," ASM_NAME(#name) "@@" #version) +-#endif + + #ifdef USE_VERSIONED_SYMBOLS + #define use_symbol_version(real, name, version) \ +@@ -50,13 +41,6 @@ + default_symbol_version(real, name, version) + #else + #define use_symbol_version(real, name, version) /* nothing */ +-#ifdef __powerpc64__ +-#define use_default_symbol_version(real, name, version) \ +- __asm__ (".weak " ASM_NAME(#name)); \ +- __asm__ (".weak ." ASM_NAME(#name)); \ +- __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)); \ +- __asm__ (".set ." ASM_NAME(#name) ",." ASM_NAME(#real)) +-#else + #if defined(__alpha__) || defined(__mips__) + #define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " ASM_NAME(#name)); \ +@@ -67,6 +51,5 @@ + __asm__ (".set " ASM_NAME(#name) "," ASM_NAME(#real)) + #endif + #endif +-#endif + + #endif /* __ALSA_SYMBOLS_H */ +-- +2.9.3 + + +From b0e4652881f883023d2b190cf3897b7494d8d0ed Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:25:24 +0100 +Subject: [PATCH 33/37] pcm_plugin: unify the snd_pcm_mmap_begin result value + checking + +--- + src/pcm/pcm_plugin.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index ad4a102..aaea2ab 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -251,8 +251,12 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + +- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); +- if (err < 0 || slave_frames == 0) ++ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ if (result < 0) { ++ err = result; ++ goto error; ++ } ++ if (slave_frames == 0) + break; + frames = plugin->write(pcm, areas, offset, frames, + slave_areas, slave_offset, &slave_frames); +@@ -304,7 +308,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + +- snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ if (result < 0) { ++ err = result; ++ goto error; ++ } + if (slave_frames == 0) + break; + frames = (plugin->read)(pcm, areas, offset, frames, +@@ -409,9 +417,11 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + +- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); +- if (err < 0) ++ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ if (result < 0) { ++ err = result; + goto error; ++ } + if (frames > cont) + frames = cont; + frames = plugin->write(pcm, areas, appl_offset, frames, +@@ -481,9 +491,11 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + +- err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); +- if (err < 0) ++ result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); ++ if (result < 0) { ++ err = result; + goto error; ++ } + if (frames > cont) + frames = cont; + frames = (plugin->read)(pcm, areas, hw_offset, frames, +-- +2.9.3 + + +From 8a38461fac67f6542308063ba8e9887a1a2fa84e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:26:33 +0100 +Subject: [PATCH 34/37] always handle return value from snd_config_get_id() + (coverity) + +--- + src/pcm/pcm_rate.c | 6 ++++-- + src/topology/data.c | 4 ++-- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 46eb797..f60b0ae 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1339,7 +1339,8 @@ static int is_string_array(const snd_config_t *conf) + if (i && i != snd_config_iterator_end(conf)) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; +- snd_config_get_id(n, &id); ++ if (snd_config_get_id(n, &id) < 0) ++ return 0; + if (id && strcmp(id, "0") != 0) + return 0; + } +@@ -1422,7 +1423,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + snd_config_for_each(i, next, converter) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; +- snd_config_get_id(n, &id); ++ if (snd_config_get_id(n, &id) < 0) ++ continue; + if (strcmp(id, "name") != 0) + continue; + snd_config_get_string(n, &type); +diff --git a/src/topology/data.c b/src/topology/data.c +index e2aa38c..8fe2342 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -653,8 +653,8 @@ static int parse_tuple_sets(snd_config_t *cfg, + int err; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { +- snd_config_get_id(cfg, &id); +- SNDERR("error: compound type expected for %s", id); ++ if (snd_config_get_id(cfg, &id) >= 0) ++ SNDERR("error: compound type expected for %s", id); + return -EINVAL; + } + +-- +2.9.3 + + +From b96f6f47852aa145645fb8626d009ec532246e55 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:29:18 +0100 +Subject: [PATCH 35/37] pcm file plugin: handle snd_pcm_mmap_begin() error path + in snd_pcm_file_mmap_commit() + +--- + src/pcm/pcm_file.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c +index 0363f84..8012251 100644 +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -593,11 +593,13 @@ static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, + const snd_pcm_channel_area_t *areas; + snd_pcm_sframes_t result; + +- snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); +- assert(ofs == offset && siz == size); +- result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); +- if (result > 0) +- snd_pcm_file_add_frames(pcm, areas, ofs, result); ++ result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz); ++ if (result >= 0) { ++ assert(ofs == offset && siz == size); ++ result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz); ++ if (result > 0) ++ snd_pcm_file_add_frames(pcm, areas, ofs, result); ++ } + return result; + } + +-- +2.9.3 + + +From db0e1dcfc22fb2e408a12993cda2d604e0fb10f8 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:46:18 +0100 +Subject: [PATCH 36/37] topology: coverity - remove dead code + +--- + src/topology/ctl.c | 5 ++--- + src/topology/data.c | 2 +- + src/topology/pcm.c | 17 +++++++---------- + 3 files changed, 10 insertions(+), 14 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 1da3d18..c026c2a 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -173,7 +173,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, + { + struct tplg_ref *ref; + struct list_head *base, *pos; +- int err = 0; ++ int err; + + base = &elem->ref_list; + +@@ -198,8 +198,7 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, + SNDERR("error: cannot find '%s' referenced by" + " control '%s'\n", ref->id, elem->id); + return -EINVAL; +- } else if (err < 0) +- return err; ++ } + } + + return 0; +diff --git a/src/topology/data.c b/src/topology/data.c +index 8fe2342..31e4ee1 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -917,7 +917,7 @@ int tplg_build_manifest_data(snd_tplg_t *tplg) + list_for_each(pos, base) { + + ref = list_entry(pos, struct tplg_ref, list); +- if (ref->id == NULL || ref->elem) ++ if (ref->elem) + continue; + + if (ref->type == SND_TPLG_TYPE_DATA) { +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 5568d57..50a373a 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -79,8 +79,8 @@ static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) + int err; + + err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps); +- if (err < 0) +- return err; ++ if (err < 0) ++ return err; + + /* merge private data from the referenced data elements */ + base = &elem->ref_list; +@@ -96,8 +96,7 @@ static int build_pcm(snd_tplg_t *tplg, struct tplg_elem *elem) + SNDERR("error: cannot find '%s' referenced by" + " PCM '%s'\n", ref->id, elem->id); + return -EINVAL; +- } else if (err < 0) +- return err; ++ } + } + + return 0; +@@ -1208,12 +1207,10 @@ int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) + + /* ID and names */ + link->id = link_tpl->id; +- if (link->name) +- elem_copy_text(link->name, link_tpl->name, +- SNDRV_CTL_ELEM_ID_NAME_MAXLEN); +- if (link->stream_name) +- elem_copy_text(link->stream_name, link_tpl->stream_name, +- SNDRV_CTL_ELEM_ID_NAME_MAXLEN); ++ elem_copy_text(link->name, link_tpl->name, ++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); ++ elem_copy_text(link->stream_name, link_tpl->stream_name, ++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + /* stream configs */ + if (link_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX) +-- +2.9.3 + + +From ad188bbf7813eab6f42dcdf617aa947107118857 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Feb 2017 09:53:26 +0100 +Subject: [PATCH 37/37] ucm parser: fix possible string overflow in + uc_mgr_import_master_config() + +--- + src/ucm/parser.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index 798bf48..b79b92d 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -1453,7 +1453,8 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) + err = load_master_config(uc_mgr->card_name, &cfg); + if (err < 0) + return err; +- strcpy(uc_mgr->conf_file_name, uc_mgr->card_name); ++ strncpy(uc_mgr->conf_file_name, uc_mgr->card_name, MAX_CARD_LONG_NAME); ++ uc_mgr->conf_file_name[MAX_CARD_LONG_NAME-1] = '\0'; + } + + err = parse_master_file(uc_mgr, cfg); +-- +2.9.3 + diff --git a/SPECS/alsa-lib.spec b/SPECS/alsa-lib.spec index a507780..babec3f 100644 --- a/SPECS/alsa-lib.spec +++ b/SPECS/alsa-lib.spec @@ -4,8 +4,8 @@ Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib -Version: 1.1.1 -Release: 1%{?prever_dot}%{?dist} +Version: 1.1.3 +Release: 3%{?prever_dot}%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.alsa-project.org/ @@ -14,11 +14,11 @@ Source: ftp://ftp.alsa-project.org/pub/lib/%{name}-%{version}%{?prever}%{?post Source10: asound.conf Source11: modprobe-dist-alsa.conf Source12: modprobe-dist-oss.conf -Patch0: alsa-lib-1.1.1-post.patch +Patch0: alsa-lib-1.1.3-post.patch Patch1: alsa-lib-1.1.0-config.patch -Patch2: alsa-lib-1.0.16-no-dox-date.patch BuildRequires: doxygen +BuildRequires: autoconf automake libtool Requires(post): /sbin/ldconfig, coreutils %description @@ -46,7 +46,7 @@ against the ALSA libraries and interfaces. %setup -q -n %{name}-%{version}%{?prever}%{?postver} %patch0 -p1 -b .post %patch1 -p1 -b .config -%patch2 -p1 -b .dox-date +autoreconf -f -i %build %configure --disable-aload --with-plugindir=%{_libdir}/alsa-lib --disable-alisp @@ -81,9 +81,11 @@ install -p -m 644 %{SOURCE12} %{buildroot}%{_defaultdocdir}/%{name}/modprobe-dis mkdir -p %{buildroot}/%{_datadir}/alsa/ucm # Remove all UCM files (should be selected by architecture) rm -rf %{buildroot}/%{_datadir}/alsa/ucm/* +# Remove smixer .so modules +rm -rf %{buildroot}/%{_libdir}/alsa-lib/smixer #Remove libtool archives. -find %{buildroot} -name '*.la' -exec rm -f {} ';' +find %{buildroot} -name '*.la' -delete %post -p /sbin/ldconfig @@ -98,7 +100,7 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';' %config %{_sysconfdir}/asound.conf /%{_lib}/libasound.so.* %{_bindir}/aserver -%{_libdir}/alsa-lib/ +#%{_libdir}/alsa-lib/ %{_datadir}/alsa/ /lib/modprobe.d/dist-* @@ -112,6 +114,10 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';' %{_datadir}/aclocal/alsa.m4 %changelog +* Wed Mar 1 2017 Jaroslav Kysela - 1.1.3-3 +- Updated to 1.1.3 +- Resolves: rhbz#1399508 + * Mon Jun 6 2016 Jaroslav Kysela - 1.1.1-1 - Updated to 1.1.1 - Resolves: rhbz#1297932