Blob Blame History Raw
From 63ba5243ab7a33b77be5b65c0a8a2a0d5e26983f Mon Sep 17 00:00:00 2001
From: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Date: Wed, 15 May 2019 11:56:32 +0530
Subject: [PATCH 01/25] pcm: direct: Add generic hw_ptr_alignment function for
 dmix, dshare and dsnoop

Move the code snd_pcm_direct_reset_slave_ptr() from pcm_dmix.c
to pcm_direct.c and its header so that the helper function can be
re-used by other direct-pcm plugins.
There is no change in the behavior or the functionality.

Signed-off-by: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_direct.c | 19 +++++++++++++++++++
 src/pcm/pcm_direct.h |  8 ++++++++
 src/pcm/pcm_dmix.c   | 25 ++-----------------------
 3 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 666a8ce5..411a035b 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -2040,3 +2040,22 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf,
 
 	return 0;
 }
+
+void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
+{
+	dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
+
+	if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP ||
+		(dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO &&
+		pcm->buffer_size <= pcm->period_size * 2))
+		dmix->slave_appl_ptr =
+			((dmix->slave_appl_ptr + dmix->slave_period_size - 1) /
+			dmix->slave_period_size) * dmix->slave_period_size;
+	else if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN ||
+		(dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO &&
+		(dmix->slave_period_size * SEC_TO_MS) /
+		pcm->rate < LOW_LATENCY_PERIOD_TIME))
+		dmix->slave_appl_ptr = dmix->slave_hw_ptr =
+			((dmix->slave_hw_ptr / dmix->slave_period_size) *
+			dmix->slave_period_size);
+}
diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h
index da5e280e..a71aab13 100644
--- a/src/pcm/pcm_direct.h
+++ b/src/pcm/pcm_direct.h
@@ -24,6 +24,11 @@
 
 #define DIRECT_IPC_SEMS         1
 #define DIRECT_IPC_SEM_CLIENT   0
+/* Seconds representing in Milli seconds */
+#define SEC_TO_MS               1000
+/* slave_period time for low latency requirements in ms */
+#define LOW_LATENCY_PERIOD_TIME 10
+
 
 typedef void (mix_areas_t)(unsigned int size,
 			   volatile void *dst, void *src,
@@ -257,6 +262,8 @@ struct snd_pcm_direct {
 	snd1_pcm_direct_get_chmap
 #define snd_pcm_direct_set_chmap \
 	snd1_pcm_direct_set_chmap
+#define snd_pcm_direct_reset_slave_ptr \
+	snd1_pcm_direct_reset_slave_ptr
 
 int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
 
@@ -341,6 +348,7 @@ 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);
+void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix);
 
 struct snd_pcm_direct_open_conf {
 	key_t ipc_key;
diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index c5592cdb..dcde40d9 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -55,9 +55,6 @@ const char *_snd_module_pcm_dmix = "";
 #define STATE_RUN_PENDING	1024
 #endif
 
-#define SEC_TO_MS	1000			/* Seconds representing in Milli seconds */
-#define LOW_LATENCY_PERIOD_TIME	10	/* slave_period time for low latency requirements in ms */
-
 /*
  *
  */
@@ -560,30 +557,12 @@ static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
 	}
 }
 
-static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
-{
-	dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
-
-	if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP ||
-	    (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO &&
-	     pcm->buffer_size <= pcm->period_size * 2))
-		dmix->slave_appl_ptr =
-			((dmix->slave_appl_ptr + dmix->slave_period_size - 1)
-			 / dmix->slave_period_size) * dmix->slave_period_size;
-	else if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDDOWN ||
-		 (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO &&
-		  (dmix->slave_period_size * SEC_TO_MS) / pcm->rate < LOW_LATENCY_PERIOD_TIME))
-		dmix->slave_appl_ptr = dmix->slave_hw_ptr =
-			((dmix->slave_hw_ptr / dmix->slave_period_size) *
-			 dmix->slave_period_size);
-}
-
 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
 {
 	snd_pcm_direct_t *dmix = pcm->private_data;
 	dmix->hw_ptr %= pcm->period_size;
 	dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
-	reset_slave_ptr(pcm, dmix);
+	snd_pcm_direct_reset_slave_ptr(pcm, dmix);
 	return 0;
 }
 
@@ -592,7 +571,7 @@ static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
 	int err;
 
 	snd_pcm_hwsync(dmix->spcm);
-	reset_slave_ptr(pcm, dmix);
+	snd_pcm_direct_reset_slave_ptr(pcm, dmix);
 	err = snd_timer_start(dmix->timer);
 	if (err < 0)
 		return err;
-- 
2.20.1


From 7265e603bf880a9ec2cd01c3cf2afbd7709e5af4 Mon Sep 17 00:00:00 2001
From: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Date: Wed, 15 May 2019 11:56:33 +0530
Subject: [PATCH 02/25] pcm: dshare: Added "hw_ptr_alignment" option in
 configuration for alignment of slave pointers

This change adapt the fix commit 6b058fda9dce
("pcm: dmix: Add option to allow alignment of slave pointers")
for dshare plugin

Issue is that snd_pcm_wait() goes back to waiting because the hw_ptr
is not period aligned. Therefore snd_pcm_wait() will block for a longer
time as required.

With these rcar driver changes the exact position of the dma is returned.
During snd_pcm_start they read hw_ptr as reference, and this hw_ptr
is now not period aligned, and is a little ahead over the period while it
is read. Therefore when the avail is calculated during snd_pcm_wait(),
it is missing the avail_min by a few frames.

An additional option hw_ptr_alignment is provided to dshare configuration,
to allow the user to configure the slave application and hw pointer
alignment at startup

Signed-off-by: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_dshare.c | 40 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 5 deletions(-)

diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index f135b5df..cf8a8631 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -333,16 +333,16 @@ static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
 	snd_pcm_direct_t *dshare = pcm->private_data;
 	dshare->hw_ptr %= pcm->period_size;
 	dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
-	dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
+	snd_pcm_direct_reset_slave_ptr(pcm, dshare);
 	return 0;
 }
 
-static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare)
+static int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare)
 {
 	int err;
 
 	snd_pcm_hwsync(dshare->spcm);
-	dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
+	snd_pcm_direct_reset_slave_ptr(pcm, dshare);
 	err = snd_timer_start(dshare->timer);
 	if (err < 0)
 		return err;
@@ -364,7 +364,8 @@ static int snd_pcm_dshare_start(snd_pcm_t *pcm)
 	else if (avail < 0)
 		return 0;
 	else {
-		if ((err = snd_pcm_dshare_start_timer(dshare)) < 0)
+		err = snd_pcm_dshare_start_timer(pcm, dshare);
+		if (err < 0)
 			return err;
 		snd_pcm_dshare_sync_area(pcm);
 	}
@@ -547,7 +548,8 @@ static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm,
 		return 0;
 	snd_pcm_mmap_appl_forward(pcm, size);
 	if (dshare->state == STATE_RUN_PENDING) {
-		if ((err = snd_pcm_dshare_start_timer(dshare)) < 0)
+		err = snd_pcm_dshare_start_timer(pcm, dshare);
+		if (err < 0)
 			return err;
 	} else if (dshare->state == SND_PCM_STATE_RUNNING ||
 		   dshare->state == SND_PCM_STATE_DRAINING) {
@@ -755,6 +757,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 	dshare->slowptr = opts->slowptr;
 	dshare->max_periods = opts->max_periods;
 	dshare->var_periodsize = opts->var_periodsize;
+	dshare->hw_ptr_alignment = opts->hw_ptr_alignment;
 	dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
 
  retry:
@@ -912,6 +915,12 @@ pcm.name {
 	ipc_key INT		# unique IPC key
 	ipc_key_add_uid BOOL	# add current uid to unique IPC key
 	ipc_perm INT		# IPC permissions (octal, default 0600)
+	hw_ptr_alignment STR	# Slave application and hw pointer alignment type
+		# STR can be one of the below strings :
+		# no
+		# roundup
+		# rounddown
+		# auto (default)
 	slave STR
 	# or
 	slave {			# Slave definition
@@ -936,6 +945,27 @@ pcm.name {
 }
 \endcode
 
+<code>hw_ptr_alignment</code> specifies slave application and hw
+pointer alignment type. By default hw_ptr_alignment is auto. Below are
+the possible configurations:
+- no: minimal latency with minimal frames dropped at startup. But
+  wakeup of application (return from snd_pcm_wait() or poll()) can
+  take up to 2 * period.
+- roundup: It is guaranteed that all frames will be played at
+  startup. But the latency will increase upto period-1 frames.
+- rounddown: It is guaranteed that a wakeup will happen for each
+  period and frames can be written from application. But on startup
+  upto period-1 frames will be dropped.
+- auto: Selects the best approach depending on the used period and
+  buffer size.
+  If the application buffer size is < 2 * application period,
+  "roundup" will be selected to avoid under runs. If the slave_period
+  is < 10ms we could expect that there are low latency
+  requirements. Therefore "rounddown" will be chosen to avoid long
+  wakeup times. Such wakeup delay could otherwise end up with Xruns in
+  case of a dependency to another sound device (e.g. forwarding of
+  microphone to speaker). Else "no" will be chosen.
+
 \subsection pcm_plugins_dshare_funcref Function reference
 
 <UL>
-- 
2.20.1


From 3ab798004733ce65bd5c7a48d650de3465825210 Mon Sep 17 00:00:00 2001
From: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Date: Wed, 15 May 2019 11:56:34 +0530
Subject: [PATCH 03/25] pcm: dsnoop: Added "hw_ptr_alignment" option in
 configuration for slave pointer alignment

This change adapt the fix commit 6b058fda9dce
("pcm: dmix: Add option to allow alignment of slave pointers")
for dsnoop plugin

Issue is that snd_pcm_wait() goes back to waiting because the hw_ptr
is not period aligned. Therefore snd_pcm_wait() will block for a longer
time as required.

With these rcar driver changes the exact position of the dma is returned.
During snd_pcm_start they read hw_ptr as reference, and this hw_ptr
is now not period aligned, and is a little ahead over the period while it
is read. Therefore when the avail is calculated during snd_pcm_wait(),
it is missing the avail_min by a few frames.

An additional option hw_ptr_alignment is provided to dsnoop configuration,
to allow the user to configure the slave application and hw pointer
alignment at startup

Signed-off-by: Vanitha Channaiah <vanitha.channaiah@in.bosch.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_direct.c |  1 -
 src/pcm/pcm_dmix.c   |  2 ++
 src/pcm/pcm_dshare.c |  2 ++
 src/pcm/pcm_dsnoop.c | 30 +++++++++++++++++++++++++++++-
 4 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 411a035b..54d99005 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -2043,7 +2043,6 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf,
 
 void snd_pcm_direct_reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
 {
-	dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
 
 	if (dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_ROUNDUP ||
 		(dmix->hw_ptr_alignment == SND_PCM_HW_PTR_ALIGNMENT_AUTO &&
diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index dcde40d9..274726e4 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -562,6 +562,7 @@ static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
 	snd_pcm_direct_t *dmix = pcm->private_data;
 	dmix->hw_ptr %= pcm->period_size;
 	dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
+	dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
 	snd_pcm_direct_reset_slave_ptr(pcm, dmix);
 	return 0;
 }
@@ -571,6 +572,7 @@ static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
 	int err;
 
 	snd_pcm_hwsync(dmix->spcm);
+	dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
 	snd_pcm_direct_reset_slave_ptr(pcm, dmix);
 	err = snd_timer_start(dmix->timer);
 	if (err < 0)
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index cf8a8631..b75809c8 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -333,6 +333,7 @@ static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
 	snd_pcm_direct_t *dshare = pcm->private_data;
 	dshare->hw_ptr %= pcm->period_size;
 	dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
+	dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
 	snd_pcm_direct_reset_slave_ptr(pcm, dshare);
 	return 0;
 }
@@ -342,6 +343,7 @@ static int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare)
 	int err;
 
 	snd_pcm_hwsync(dshare->spcm);
+	dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
 	snd_pcm_direct_reset_slave_ptr(pcm, dshare);
 	err = snd_timer_start(dshare->timer);
 	if (err < 0)
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index d08b6241..58b1e534 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -278,6 +278,7 @@ static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
 	dsnoop->hw_ptr %= pcm->period_size;
 	dsnoop->appl_ptr = dsnoop->hw_ptr;
 	dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
+	snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
 	return 0;
 }
 
@@ -285,12 +286,13 @@ static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
 {
 	snd_pcm_direct_t *dsnoop = pcm->private_data;
 	int err;
-	
+
 	if (dsnoop->state != SND_PCM_STATE_PREPARED)
 		return -EBADFD;
 	snd_pcm_hwsync(dsnoop->spcm);
 	snoop_timestamp(pcm);
 	dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
+	snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
 	err = snd_timer_start(dsnoop->timer);
 	if (err < 0)
 		return err;
@@ -627,6 +629,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 	dsnoop->max_periods = opts->max_periods;
 	dsnoop->var_periodsize = opts->var_periodsize;
 	dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
+	dsnoop->hw_ptr_alignment = opts->hw_ptr_alignment;
 
  retry:
 	if (first_instance) {
@@ -771,6 +774,12 @@ pcm.name {
 	ipc_key INT		# unique IPC key
 	ipc_key_add_uid BOOL	# add current uid to unique IPC key
 	ipc_perm INT		# IPC permissions (octal, default 0600)
+	hw_ptr_alignment STR	# Slave application and hw pointer alignment type
+		# STR can be one of the below strings :
+		# no
+		# roundup
+		# rounddown
+		# auto (default)
 	slave STR
 	# or
 	slave {			# Slave definition
@@ -795,6 +804,25 @@ pcm.name {
 }
 \endcode
 
+<code>hw_ptr_alignment</code> specifies slave application and hw
+pointer alignment type. By default hw_ptr_alignment is auto. Below are
+the possible configurations:
+- no: minimal latency with minimal frames dropped at startup. But
+  wakeup of application (return from snd_pcm_wait() or poll()) can
+  take up to 2 * period.
+- roundup: It is guaranteed that all frames will be played at
+  startup. But the latency will increase upto period-1 frames.
+- rounddown: It is guaranteed that a wakeup will happen for each
+  period and frames can be written from application. But on startup
+  upto period-1 frames will be dropped.
+- auto: Selects the best approach depending on the used period and
+  buffer size.
+  If the application buffer size is < 2 * application period,
+  "roundup" will be selected to avoid over runs. If the slave_period
+  is < 10ms we could expect that there are low latency
+  requirements. Therefore "rounddown" will be chosen to avoid long
+  wakeup times. Else "no" will be chosen.
+
 \subsection pcm_plugins_dsnoop_funcref Function reference
 
 <UL>
-- 
2.20.1


From 5f2e5af61b0b8cfbf310e8b1e08a034d993e432f Mon Sep 17 00:00:00 2001
From: Adam Miartus <amiartus@de.adit-jv.com>
Date: Tue, 21 May 2019 15:32:47 +0200
Subject: [PATCH 04/25] pcm: file: add support for infile reading in non
 interleaved mode

add helper function to copy input file data to buffer mapped by areas,
in case of an error, do not fill the areas, allowing device read buffer
to be provided to api caller

previously unused rbuf variable is reused for this purpose

Signed-off-by: Adam Miartus <amiartus@de.adit-jv.com>
Reviewed-by: Timo Wischer <twischer@de.adit-jv.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_file.c | 67 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 56 insertions(+), 11 deletions(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 3a19cef9..3c682659 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -77,6 +77,7 @@ typedef struct {
 	snd_pcm_uframes_t appl_ptr;
 	snd_pcm_uframes_t file_ptr_bytes;
 	snd_pcm_uframes_t wbuf_size;
+	snd_pcm_uframes_t rbuf_size;
 	size_t wbuf_size_bytes;
 	size_t wbuf_used_bytes;
 	char *wbuf;
@@ -266,6 +267,39 @@ static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
 	return 0;
 }
 
+/* fill areas with data from input file, return bytes red */
+static int snd_pcm_file_areas_read_infile(snd_pcm_t *pcm,
+					  const snd_pcm_channel_area_t *areas,
+					  snd_pcm_uframes_t offset,
+					  snd_pcm_uframes_t frames)
+{
+	snd_pcm_file_t *file = pcm->private_data;
+	snd_pcm_channel_area_t areas_if[pcm->channels];
+	ssize_t bytes;
+
+	if (file->ifd < 0)
+		return -EBADF;
+
+	if (file->rbuf == NULL)
+		return -ENOMEM;
+
+	if (file->rbuf_size < frames) {
+		SYSERR("requested more frames than pcm buffer");
+		return -ENOMEM;
+	}
+
+	bytes = read(file->ifd, file->rbuf, snd_pcm_frames_to_bytes(pcm, frames));
+	if (bytes < 0) {
+		SYSERR("read from file failed, error: %d", bytes);
+		return bytes;
+	}
+
+	snd_pcm_areas_from_buf(pcm, areas_if, file->rbuf);
+	snd_pcm_areas_copy(areas, offset, areas_if, 0, pcm->channels, snd_pcm_bytes_to_frames(pcm, bytes), pcm->format);
+
+	return bytes;
+}
+
 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
 {
 	fmt->fmt = TO_LE16(0x01);
@@ -568,19 +602,19 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm
 {
 	snd_pcm_file_t *file = pcm->private_data;
 	snd_pcm_channel_area_t areas[pcm->channels];
-	snd_pcm_sframes_t n;
+	snd_pcm_sframes_t frames;
 
-	if (file->ifd >= 0) {
-		SNDERR("DEBUG: Noninterleaved read not yet implemented.\n");
-		return 0;	/* TODO: Noninterleaved read */
-	}
+	__snd_pcm_lock(pcm);
+	frames = _snd_pcm_readn(file->gen.slave, bufs, size);
+	if (frames <= 0)
+		return frames;
 
-	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;
+	snd_pcm_areas_from_bufs(pcm, areas, bufs);
+	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
+	snd_pcm_file_add_frames(pcm, areas, 0, frames);
+
+	__snd_pcm_unlock(pcm);
+	return frames;
 }
 
 static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
@@ -609,9 +643,11 @@ static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
 	free(file->wbuf);
 	free(file->wbuf_areas);
 	free(file->final_fname);
+	free(file->rbuf);
 	file->wbuf = NULL;
 	file->wbuf_areas = NULL;
 	file->final_fname = NULL;
+	file->rbuf = NULL;
 	return snd_pcm_hw_free(file->gen.slave);
 }
 
@@ -638,6 +674,15 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		snd_pcm_file_hw_free(pcm);
 		return -ENOMEM;
 	}
+	assert(!file->rbuf);
+	file->rbuf_size = slave->buffer_size;
+	file->rbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->rbuf_size);
+	file->rbuf_used_bytes = 0;
+	file->rbuf = malloc(file->rbuf_size_bytes);
+	if (file->rbuf == NULL) {
+		snd_pcm_file_hw_free(pcm);
+		return -ENOMEM;
+	}
 	file->appl_ptr = file->file_ptr_bytes = 0;
 	for (channel = 0; channel < slave->channels; ++channel) {
 		snd_pcm_channel_area_t *a = &file->wbuf_areas[channel];
-- 
2.20.1


From 349b42f5477c904fa3e10bac2fa2429fad2cbc65 Mon Sep 17 00:00:00 2001
From: Adam Miartus <amiartus@de.adit-jv.com>
Date: Tue, 21 May 2019 15:33:08 +0200
Subject: [PATCH 05/25] pcm: file: use snd_pcm_file_areas_read_infile for readi

use previously introduced helper function, this commit unifies behavior
of readi and readn

corner case behavior of readi is changed by this commit, previously,
in case 0 bytes were red from file (EOF), frames = 0 was returned,
signaling api user as if no data was red from slave, after the patch,
amount of frames red from slave with data red from slave stored in buffer
is returned when EOF is reached

Signed-off-by: Adam Miartus <amiartus@de.adit-jv.com>
Reviewed-by: Timo Wischer <twischer@de.adit-jv.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_file.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 3c682659..dcaa41d1 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -579,22 +579,21 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc
 {
 	snd_pcm_file_t *file = pcm->private_data;
 	snd_pcm_channel_area_t areas[pcm->channels];
-	snd_pcm_sframes_t n;
+	snd_pcm_sframes_t frames;
+
+	__snd_pcm_lock(pcm);
+
+	frames = _snd_pcm_readi(file->gen.slave, buffer, size);
+	if (frames <= 0)
+		return frames;
 
-	n = _snd_pcm_readi(file->gen.slave, buffer, size);
-	if (n <= 0)
-		return n;
-	if (file->ifd >= 0) {
-		__snd_pcm_lock(pcm);
-		n = read(file->ifd, buffer, n * pcm->frame_bits / 8);
-		__snd_pcm_unlock(pcm);
-		if (n < 0)
-			return n;
-		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;
+	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
+	snd_pcm_file_add_frames(pcm, areas, 0, frames);
+
+	__snd_pcm_unlock(pcm);
+
+	return frames;
 }
 
 /* locking */
-- 
2.20.1


From 33c7ea0865b7f87cef1c3d3e767734c0edd02e84 Mon Sep 17 00:00:00 2001
From: Adam Miartus <amiartus@de.adit-jv.com>
Date: Thu, 23 May 2019 11:44:30 +0200
Subject: [PATCH 06/25] pcm: file: add missing unlock on early return

Signed-off-by: Adam Miartus <amiartus@de.adit-jv.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_file.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index dcaa41d1..8e2c70b1 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -584,8 +584,10 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc
 	__snd_pcm_lock(pcm);
 
 	frames = _snd_pcm_readi(file->gen.slave, buffer, size);
-	if (frames <= 0)
+	if (frames <= 0) {
+		__snd_pcm_unlock(pcm);
 		return frames;
+	}
 
 	snd_pcm_areas_from_buf(pcm, areas, buffer);
 	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
@@ -605,8 +607,10 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm
 
 	__snd_pcm_lock(pcm);
 	frames = _snd_pcm_readn(file->gen.slave, bufs, size);
-	if (frames <= 0)
+	if (frames <= 0) {
+		__snd_pcm_unlock(pcm);
 		return frames;
+	}
 
 	snd_pcm_areas_from_bufs(pcm, areas, bufs);
 	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
-- 
2.20.1


From 108a2f43791fe769fd58726881b12ad908ebd2e0 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 18 Apr 2019 20:40:18 +0200
Subject: [PATCH 07/25] ucm: Add UCM profile for CX2072X codec on
 Baytrail/Cherrytrail profiles

Adding a new Conexant CX2072X codec profile and reusing the existing
BYT/CHT platform snippets.

Currently tested only on ASUS E200HA laptop.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 configure.ac                                  |  2 ++
 src/conf/ucm/Makefile.am                      |  1 +
 src/conf/ucm/bytcht-cx2072x/HiFi.conf         | 24 ++++++++++++++++++
 src/conf/ucm/bytcht-cx2072x/Makefile.am       |  4 +++
 .../ucm/bytcht-cx2072x/bytcht-cx2072x.conf    |  8 ++++++
 src/conf/ucm/codecs/Makefile.am               |  1 +
 src/conf/ucm/codecs/cx2072x/DisableSeq.conf   |  7 ++++++
 src/conf/ucm/codecs/cx2072x/EnableSeq.conf    | 13 ++++++++++
 src/conf/ucm/codecs/cx2072x/HeadPhones.conf   | 24 ++++++++++++++++++
 src/conf/ucm/codecs/cx2072x/HeadsetMic.conf   | 25 +++++++++++++++++++
 src/conf/ucm/codecs/cx2072x/InternalMic.conf  | 24 ++++++++++++++++++
 src/conf/ucm/codecs/cx2072x/Makefile.am       |  6 +++++
 src/conf/ucm/codecs/cx2072x/Speaker.conf      | 23 +++++++++++++++++
 13 files changed, 162 insertions(+)
 create mode 100644 src/conf/ucm/bytcht-cx2072x/HiFi.conf
 create mode 100644 src/conf/ucm/bytcht-cx2072x/Makefile.am
 create mode 100644 src/conf/ucm/bytcht-cx2072x/bytcht-cx2072x.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/DisableSeq.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/EnableSeq.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/HeadPhones.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/HeadsetMic.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/InternalMic.conf
 create mode 100644 src/conf/ucm/codecs/cx2072x/Makefile.am
 create mode 100644 src/conf/ucm/codecs/cx2072x/Speaker.conf

diff --git a/configure.ac b/configure.ac
index 0fb34de4..2e955760 100644
--- a/configure.ac
+++ b/configure.ac
@@ -720,6 +720,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/conf/ucm/ASUSTeKCOMPUTERINC.-T100HAN-1.0-T100HAN/Makefile \
 	  src/conf/ucm/broadwell-rt286/Makefile \
 	  src/conf/ucm/broxton-rt298/Makefile \
+	  src/conf/ucm/bytcht-cx2072x/Makefile \
 	  src/conf/ucm/bytcht-es8316/Makefile \
 	  src/conf/ucm/bytcht-es8316-mono-spk-in1-mic/Makefile \
 	  src/conf/ucm/bytcht-es8316-mono-spk-in2-mic/Makefile \
@@ -765,6 +766,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
 	  src/conf/ucm/tegraalc5632/Makefile \
 	  src/conf/ucm/VEYRON-I2S/Makefile \
 	  src/conf/ucm/codecs/Makefile \
+	  src/conf/ucm/codecs/cx2072x/Makefile \
 	  src/conf/ucm/codecs/es8316/Makefile \
 	  src/conf/ucm/codecs/nau8824/Makefile \
 	  src/conf/ucm/codecs/rt5640/Makefile \
diff --git a/src/conf/ucm/Makefile.am b/src/conf/ucm/Makefile.am
index e9f88ed6..02257048 100644
--- a/src/conf/ucm/Makefile.am
+++ b/src/conf/ucm/Makefile.am
@@ -4,6 +4,7 @@ platforms \
 ASUSTeKCOMPUTERINC.-T100HAN-1.0-T100HAN \
 broadwell-rt286 \
 broxton-rt298 \
+bytcht-cx2072x \
 bytcht-es8316 \
 bytcht-es8316-mono-spk-in1-mic \
 bytcht-es8316-mono-spk-in2-mic \
diff --git a/src/conf/ucm/bytcht-cx2072x/HiFi.conf b/src/conf/ucm/bytcht-cx2072x/HiFi.conf
new file mode 100644
index 00000000..e9c1f757
--- /dev/null
+++ b/src/conf/ucm/bytcht-cx2072x/HiFi.conf
@@ -0,0 +1,24 @@
+SectionVerb {
+	EnableSequence [
+		cdev "hw:bytchtcx2072x"
+		<platforms/bytcr/PlatformEnableSeq.conf>
+		<codecs/cx2072x/EnableSeq.conf>
+	]
+
+	DisableSequence [
+		cdev "hw:bytchtcx2072x"
+		<codecs/cx2072x/DisableSeq.conf>
+		<platforms/bytcr/PlatformDisableSeq.conf>
+	]
+
+	Value {
+		PlaybackPCM "hw:bytchtcx2072x"
+		CapturePCM "hw:bytchtcx2072x"
+	}
+}
+
+<codecs/cx2072x/Speaker.conf>
+<codecs/cx2072x/HeadPhones.conf>
+
+<codecs/cx2072x/InternalMic.conf>
+<codecs/cx2072x/HeadsetMic.conf>
diff --git a/src/conf/ucm/bytcht-cx2072x/Makefile.am b/src/conf/ucm/bytcht-cx2072x/Makefile.am
new file mode 100644
index 00000000..373b2a77
--- /dev/null
+++ b/src/conf/ucm/bytcht-cx2072x/Makefile.am
@@ -0,0 +1,4 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+ucmdir = $(alsaconfigdir)/ucm/bytcht-cx2072x
+ucm_DATA = bytcht-cx2072x.conf HiFi.conf
+EXTRA_DIST = $(ucm_DATA)
diff --git a/src/conf/ucm/bytcht-cx2072x/bytcht-cx2072x.conf b/src/conf/ucm/bytcht-cx2072x/bytcht-cx2072x.conf
new file mode 100644
index 00000000..fce04456
--- /dev/null
+++ b/src/conf/ucm/bytcht-cx2072x/bytcht-cx2072x.conf
@@ -0,0 +1,8 @@
+SectionUseCase."HiFi" {
+	File "HiFi.conf"
+	Comment "Play HiFi quality Music"
+}
+
+SectionDefaults [
+	cdev "hw:bytchtcx2072x"
+]
diff --git a/src/conf/ucm/codecs/Makefile.am b/src/conf/ucm/codecs/Makefile.am
index f78fd081..5987b9cf 100644
--- a/src/conf/ucm/codecs/Makefile.am
+++ b/src/conf/ucm/codecs/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS=\
+cx2072x \
 es8316 \
 rt5640 \
 rt5645 \
diff --git a/src/conf/ucm/codecs/cx2072x/DisableSeq.conf b/src/conf/ucm/codecs/cx2072x/DisableSeq.conf
new file mode 100644
index 00000000..1e3d5489
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/DisableSeq.conf
@@ -0,0 +1,7 @@
+# Output Configuration
+cset "name='I2S DAC1L Switch' off"
+cset "name='I2S DAC1R Switch' off"
+
+# Input Configuration
+cset "name='I2S ADC1L Switch' off"
+cset "name='I2S ADC1R Switch' off"
diff --git a/src/conf/ucm/codecs/cx2072x/EnableSeq.conf b/src/conf/ucm/codecs/cx2072x/EnableSeq.conf
new file mode 100644
index 00000000..fb8e3fe2
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/EnableSeq.conf
@@ -0,0 +1,13 @@
+# Disable all inputs / outputs
+cset "name='Ext Spk Switch' off"
+cset "name='Headphone Switch' off"
+cset "name='Headset Mic Switch' off"
+cset "name='Int Mic Switch' off"
+
+# Output Configuration
+cset "name='I2S DAC1L Switch' on"
+cset "name='I2S DAC1R Switch' on"
+
+# Input Configuration
+cset "name='I2S ADC1L Switch' on"
+cset "name='I2S ADC1R Switch' on"
diff --git a/src/conf/ucm/codecs/cx2072x/HeadPhones.conf b/src/conf/ucm/codecs/cx2072x/HeadPhones.conf
new file mode 100644
index 00000000..4e3ff950
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/HeadPhones.conf
@@ -0,0 +1,24 @@
+SectionDevice."Headphones" {
+	Comment "Headphones"
+
+	ConflictingDevice [
+		"Speaker"
+	]
+
+	EnableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Headphone Switch' on"
+		cset "name='PortA Out En Switch' on"
+	]
+
+	DisableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Headphone Switch' off"
+		cset "name='PortA Out En Switch' off"
+	]
+
+	Value {
+		PlaybackChannels "2"
+		JackControl "Headphone Jack"
+	}
+}
diff --git a/src/conf/ucm/codecs/cx2072x/HeadsetMic.conf b/src/conf/ucm/codecs/cx2072x/HeadsetMic.conf
new file mode 100644
index 00000000..26b8df16
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/HeadsetMic.conf
@@ -0,0 +1,25 @@
+SectionDevice."HeadsetMic" {
+	Comment "Headset Microphone"
+
+	ConflictingDevice [
+		"InternalMic"
+	]
+
+	EnableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Headset Mic Switch' on"
+		cset "name='ADC1 Mux' 'PortD Switch'"
+		cset "name='PortD In En Switch' on"
+	]
+
+	DisableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Headset Mic Switch' off"
+		cset "name='PortD In En Switch' off"
+	]
+
+	Value {
+		CaptureChannels "2"
+		JackControl "Headset Mic Jack"
+	}
+}
diff --git a/src/conf/ucm/codecs/cx2072x/InternalMic.conf b/src/conf/ucm/codecs/cx2072x/InternalMic.conf
new file mode 100644
index 00000000..a3e14538
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/InternalMic.conf
@@ -0,0 +1,24 @@
+SectionDevice."InternalMic" {
+	Comment "Internal Microphone"
+
+	ConflictingDevice [
+		"HeadsetMic"
+	]
+
+	EnableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Int Mic Switch' on"
+		cset "name='ADC1 Mux' 'PortC Switch'"
+		cset "name='PortC In En Switch' on"
+	]
+
+	DisableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Int Mic Switch' off"
+		cset "name='PortC In En Switch' off"
+	]
+
+	Value {
+		CaptureChannels "2"
+	}
+}
diff --git a/src/conf/ucm/codecs/cx2072x/Makefile.am b/src/conf/ucm/codecs/cx2072x/Makefile.am
new file mode 100644
index 00000000..2990fd09
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/Makefile.am
@@ -0,0 +1,6 @@
+alsaconfigdir = @ALSA_CONFIG_DIR@
+ucmdir = $(alsaconfigdir)/ucm/codecs/cx2072x
+ucm_DATA = EnableSeq.conf DisableSeq.conf \
+	HeadPhones.conf Speaker.conf \
+	InternalMic.conf HeadsetMic.conf
+EXTRA_DIST = $(ucm_DATA)
diff --git a/src/conf/ucm/codecs/cx2072x/Speaker.conf b/src/conf/ucm/codecs/cx2072x/Speaker.conf
new file mode 100644
index 00000000..55e2b2ba
--- /dev/null
+++ b/src/conf/ucm/codecs/cx2072x/Speaker.conf
@@ -0,0 +1,23 @@
+SectionDevice."Speaker" {
+	Comment "Speakers"
+
+	ConflictingDevice [
+		"Headphones"
+	]
+
+	EnableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Ext Spk Switch' on"
+		cset "name='PortG Out En Switch' on"
+	]
+
+	DisableSequence [
+		cdev "hw:bytchtcx2072x"
+		cset "name='Ext Spk Switch' off"
+		cset "name='PortG Out En Switch' off"
+	]
+
+	Value {
+		PlaybackChannels "2"
+	}
+}
-- 
2.20.1


From e520f454803acfdb9af5cd7224129b37904eef4a Mon Sep 17 00:00:00 2001
From: Adam Miartus <amiartus@de.adit-jv.com>
Date: Thu, 23 May 2019 15:00:39 +0200
Subject: [PATCH 08/25] pcm: add mmap_begin callback to snd_pcm_fast_ops_t api

main motivation for adding the callback is to use it to enable operation
on mmaped buffer before user access for pcm_file plugin

support for MMAP read access with masking by data from input file is not
implemented for pcm_file plugin, by adding this callback implementing
such feature can be done by rewriting next continuous portion of buffer
on each mmap_begin call

plugins like softvol use pcm_plugin interface and overwrite the buffer by
looping around it in avail_update callback, this patch hopes to simplify
the task by adding new api callback, removing the need for rewriting
pcm_file (to use pcm_plugin callbacks) and careful checking when looping
around whole mmaped buffer

Signed-off-by: Adam Miartus <amiartus@de.adit-jv.com>
Reviewed-by: Timo Wischer <twischer@de.adit-jv.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm.c       | 6 ++++++
 src/pcm/pcm_local.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 3a71d79b..323926e1 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7129,7 +7129,13 @@ int __snd_pcm_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
 	snd_pcm_uframes_t f;
 	snd_pcm_uframes_t avail;
 	const snd_pcm_channel_area_t *xareas;
+
 	assert(pcm && areas && offset && frames);
+
+	if (pcm->fast_ops->mmap_begin)
+		return pcm->fast_ops->mmap_begin(pcm->fast_op_arg, areas, offset, frames);
+
+	/* fallback for plugins that do not specify new callback */
 	xareas = snd_pcm_mmap_areas(pcm);
 	if (xareas == NULL)
 		return -EBADFD;
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index d52229d8..d5726eb2 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -184,6 +184,7 @@ typedef struct {
 	int (*poll_descriptors)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); /* locked */
 	int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); /* locked */
 	int (*may_wait_for_avail_min)(snd_pcm_t *pcm, snd_pcm_uframes_t avail);
+	int (*mmap_begin)(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); /* locked */
 } snd_pcm_fast_ops_t;
 
 struct _snd_pcm {
-- 
2.20.1


From fe7ff721a954c3f8c2183febc7c3fa5736357b67 Mon Sep 17 00:00:00 2001
From: Adam Miartus <amiartus@de.adit-jv.com>
Date: Thu, 23 May 2019 15:00:40 +0200
Subject: [PATCH 09/25] pcm: file: add infile read support for mmap mode

mmap_begin callback is used to copy data from input file to mmaped
buffer

guard for corner use of api (multiple mmap_begin calls by user) is
introduced to check if next continuous buffer was already overwritten

buffer is overwritten with input file data only in case of stream capture

Signed-off-by: Adam Miartus <amiartus@de.adit-jv.com>
Reviewed-by: Timo Wischer <twischer@de.adit-jv.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_file.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 8e2c70b1..52cc10a9 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -88,6 +88,7 @@ typedef struct {
 	size_t buffer_bytes;
 	struct wav_fmt wav_header;
 	size_t filelen;
+	char ifmmap_overwritten;
 } snd_pcm_file_t;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -630,6 +631,8 @@ 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;
 
+	file->ifmmap_overwritten = 0;
+
 	result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz);
 	if (result >= 0) {
 		assert(ofs == offset && siz == size);
@@ -640,6 +643,32 @@ static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
 	return result;
 }
 
+static int snd_pcm_file_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
+	snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
+{
+	snd_pcm_file_t *file = pcm->private_data;
+	snd_pcm_channel_area_t areas_if[pcm->channels];
+	snd_pcm_uframes_t frames_if;
+	void *buffer = NULL;
+	int result;
+
+	result = snd_pcm_mmap_begin(file->gen.slave, areas, offset, frames);
+	if (result < 0)
+		return result;
+
+	if (pcm->stream != SND_PCM_STREAM_CAPTURE)
+		return result;
+
+	/* user may run mmap_begin without mmap_commit multiple times in row */
+	if (file->ifmmap_overwritten)
+		return result;
+	file->ifmmap_overwritten = 1;
+
+	snd_pcm_file_areas_read_infile(pcm, *areas, *offset, *frames);
+
+	return result;
+}
+
 static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
 {
 	snd_pcm_file_t *file = pcm->private_data;
@@ -666,6 +695,7 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 	file->wbuf_size = slave->buffer_size * 2;
 	file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size);
 	file->wbuf_used_bytes = 0;
+	file->ifmmap_overwritten = 0;
 	assert(!file->wbuf);
 	file->wbuf = malloc(file->wbuf_size_bytes);
 	if (file->wbuf == NULL) {
@@ -777,6 +807,7 @@ static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
 	.poll_descriptors = snd_pcm_generic_poll_descriptors,
 	.poll_revents = snd_pcm_generic_poll_revents,
 	.htimestamp = snd_pcm_generic_htimestamp,
+	.mmap_begin = snd_pcm_file_mmap_begin,
 };
 
 /**
-- 
2.20.1


From 47bc6d534102aca9cc2aed1b6bdd5633ef645a3f Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:27:25 +0200
Subject: [PATCH 10/25] aserver: fix resource leak coverity

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 aserver/aserver.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/aserver/aserver.c b/aserver/aserver.c
index 066414d8..6d20f330 100644
--- a/aserver/aserver.c
+++ b/aserver/aserver.c
@@ -75,6 +75,7 @@ static int make_local_socket(const char *filename)
 	if (bind(sock, (struct sockaddr *) addr, size) < 0) {
 		int result = -errno;
 		SYSERROR("bind failed");
+		close(sock);
 		return result;
 	}
 
@@ -101,6 +102,7 @@ static int make_inet_socket(int port)
 	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 		int result = -errno;
 		SYSERROR("bind failed");
+		close(sock);
 		return result;
 	}
 
@@ -916,10 +918,9 @@ static int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED
 
 static int server(const char *sockname, int port)
 {
-	int err;
+	int err, result, sockn = -1, socki = -1;
 	unsigned int k;
 	long open_max;
-	int result;
 
 	if (!sockname && port < 0)
 		return -EINVAL;
@@ -933,36 +934,36 @@ static int server(const char *sockname, int port)
 	waiters = calloc((size_t) open_max, sizeof(*waiters));
 
 	if (sockname) {
-		int sock = make_local_socket(sockname);
-		if (sock < 0)
-			return sock;
-		if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+		sockn = make_local_socket(sockname);
+		if (sockn < 0)
+			return sockn;
+		if (fcntl(sockn, F_SETFL, O_NONBLOCK) < 0) {
 			result = -errno;
 			SYSERROR("fcntl O_NONBLOCK failed");
 			goto _end;
 		}
-		if (listen(sock, 4) < 0) {
+		if (listen(sockn, 4) < 0) {
 			result = -errno;
 			SYSERROR("listen failed");
 			goto _end;
 		}
-		add_waiter(sock, POLLIN, local_handler, NULL);
+		add_waiter(sockn, POLLIN, local_handler, NULL);
 	}
 	if (port >= 0) {
-		int sock = make_inet_socket(port);
-		if (sock < 0)
-			return sock;
-		if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+		socki = make_inet_socket(port);
+		if (socki < 0)
+			return socki;
+		if (fcntl(socki, F_SETFL, O_NONBLOCK) < 0) {
 			result = -errno;
 			SYSERROR("fcntl failed");
 			goto _end;
 		}
-		if (listen(sock, 4) < 0) {
+		if (listen(socki, 4) < 0) {
 			result = -errno;
 			SYSERROR("listen failed");
 			goto _end;
 		}
-		add_waiter(sock, POLLIN, inet_handler, NULL);
+		add_waiter(socki, POLLIN, inet_handler, NULL);
 	}
 
 	while (1) {
@@ -991,6 +992,10 @@ static int server(const char *sockname, int port)
 		}
 	}
  _end:
+	if (sockn >= 0)
+		close(sockn);
+	if (socki >= 0)
+		close(socki);
 	free(pollfds);
 	free(waiters);
 	return result;
-- 
2.20.1


From 4aa960c48b4d292425597d283f3ef15d02590082 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:39:05 +0200
Subject: [PATCH 11/25] src/conf.c: add missing va_end() call (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/conf.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/conf.c b/src/conf.c
index cda5518e..3a3c91bf 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -3034,8 +3034,10 @@ int snd_config_save(snd_config_t *config, snd_output_t *out)
 		if (!k) \
 			break; \
 		err = fcn(config, k, &n); \
-		if (err < 0) \
+		if (err < 0) { \
+			va_end(arg); \
 			return err; \
+		} \
 		config = n; \
 	} \
 	va_end(arg); \
@@ -3056,8 +3058,10 @@ int snd_config_save(snd_config_t *config, snd_output_t *out)
 		if (!k) \
 			break; \
 		err = fcn(root, config, k, &n); \
-		if (err < 0) \
+		if (err < 0) { \
+			va_end(arg); \
 			return err; \
+		} \
 		config = n; \
 	} \
 	va_end(arg); \
-- 
2.20.1


From 990b1a53ed800caac0bab1c2b7987205569861fe Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:44:49 +0200
Subject: [PATCH 12/25] config: parse_string() fix the dynamic buffer
 allocation failure code (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/conf.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/conf.c b/src/conf.c
index 3a3c91bf..3e4b76a3 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -4747,8 +4747,11 @@ static int parse_string(const char **ptr, char **val)
 			return -EINVAL;
 		case '\\':
 			c = parse_char(ptr);
-			if (c < 0)
+			if (c < 0) {
+				if (alloc > bufsize)
+					free(buf);
 				return c;
+			}
 			break;
 		default:
 			(*ptr)++;
@@ -4768,12 +4771,17 @@ static int parse_string(const char **ptr, char **val)
 			alloc *= 2;
 			if (old_alloc == bufsize) {
 				buf = malloc(alloc);
+				if (!buf)
+					return -ENOMEM;
 				memcpy(buf, _buf, old_alloc);
 			} else {
-				buf = realloc(buf, alloc);
+				char *buf2 = realloc(buf, alloc);
+				if (!buf2) {
+					free(buf);
+					return -ENOMEM;
+				}
+				buf = buf2;
 			}
-			if (!buf)
-				return -ENOMEM;
 		}
 		buf[idx++] = c;
 	}
-- 
2.20.1


From 51881cacc05e7d5e3cc8fc1ec9a4ac93a6327703 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:51:47 +0200
Subject: [PATCH 13/25] control_shm: remove duplicate code (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/control/control_shm.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/src/control/control_shm.c b/src/control/control_shm.c
index d7b41398..1d9de8b7 100644
--- a/src/control/control_shm.c
+++ b/src/control/control_shm.c
@@ -302,13 +302,9 @@ static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
 {
 	snd_ctl_shm_t *shm = ctl->private_data;
 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
-	int err;
 	ctrl->u.pcm_prefer_subdevice = subdev;
 	ctrl->cmd = SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
-	err = snd_ctl_shm_action(ctl);
-	if (err < 0)
-		return err;
-	return err;
+	return snd_ctl_shm_action(ctl);
 }
 
 static int snd_ctl_shm_rawmidi_next_device(snd_ctl_t *ctl, int * device)
@@ -343,26 +339,18 @@ static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
 {
 	snd_ctl_shm_t *shm = ctl->private_data;
 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
-	int err;
 	ctrl->u.rawmidi_prefer_subdevice = subdev;
 	ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE;
-	err = snd_ctl_shm_action(ctl);
-	if (err < 0)
-		return err;
-	return err;
+	return snd_ctl_shm_action(ctl);
 }
 
 static int snd_ctl_shm_set_power_state(snd_ctl_t *ctl, unsigned int state)
 {
 	snd_ctl_shm_t *shm = ctl->private_data;
 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
-	int err;
 	ctrl->u.power_state = state;
 	ctrl->cmd = SNDRV_CTL_IOCTL_POWER;
-	err = snd_ctl_shm_action(ctl);
-	if (err < 0)
-		return err;
-	return err;
+	return snd_ctl_shm_action(ctl);
 }
 
 static int snd_ctl_shm_get_power_state(snd_ctl_t *ctl, unsigned int *state)
-- 
2.20.1


From d6ba264038fde08baf5e62bdde2a5614792db5c8 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:53:09 +0200
Subject: [PATCH 14/25] control_shm: add missing socket close to the error path
 (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/control/control_shm.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/control/control_shm.c b/src/control/control_shm.c
index 1d9de8b7..40d42643 100644
--- a/src/control/control_shm.c
+++ b/src/control/control_shm.c
@@ -424,8 +424,10 @@ static int make_local_socket(const char *filename)
 	addr->sun_family = AF_LOCAL;
 	memcpy(addr->sun_path, filename, l);
 
-	if (connect(sock, (struct sockaddr *) addr, size) < 0)
+	if (connect(sock, (struct sockaddr *) addr, size) < 0) {
+		close(sock);
 		return -errno;
+	}
 	return sock;
 }
 
-- 
2.20.1


From d5a1cf35b710d255508e56ed19633e1fbf41a2d4 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 10:57:20 +0200
Subject: [PATCH 15/25] pcm: fix memory leak in _snd_pcm_parse_config_chmaps()
 (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 323926e1..fa51ca99 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -8391,6 +8391,7 @@ _snd_pcm_parse_config_chmaps(snd_config_t *conf)
 			free(chmap);
 			goto error;
 		}
+		free(chmap);
 		nums++;
 	}
 	return maps;
-- 
2.20.1


From 22ade9b8c150240a960ca683ee6d8f53ce8bc6ea Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 11:09:43 +0200
Subject: [PATCH 16/25] pcm_file: call pclose() correctly for popen()
 (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_file.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 52cc10a9..99db3754 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -227,7 +227,14 @@ static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
 					file->final_fname);
 			return -errno;
 		}
-		fd = fileno(pipe);
+		fd = dup(fileno(pipe));
+		err = -errno;
+		pclose(pipe);
+		if (fd < 0) {
+			SYSERR("unable to dup pipe file handle for command %s",
+					file->final_fname);
+			return err;
+		}
 	} else {
 		if (file->trunc)
 			fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
-- 
2.20.1


From 3ae743efea704c16c9464f38d502c23759b71245 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 11:11:46 +0200
Subject: [PATCH 17/25] pcm_hw: close file descriptor in the error path in
 snd_pcm_hw_open() (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_hw.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index 91370a88..77d4dae1 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -1724,12 +1724,15 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
 		}
 		if (info.subdevice != (unsigned int) subdevice) {
 			close(fd);
+			fd = -1;
 			goto __again;
 		}
 	}
 	snd_ctl_close(ctl);
 	return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl);
        _err:
+	if (fd >= 0)
+		close(fd);
 	snd_ctl_close(ctl);
 	return ret;
 }
-- 
2.20.1


From 8ab0393b42e08655a5fee0a8e84b3ba84932465b Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 20:31:24 +0200
Subject: [PATCH 18/25] rawmidi: use snd_dlobj_cache_get2() in rawmidi open
 (coverity)

Use proper reference counting for the dynamic symbol.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 include/local.h             |  3 +++
 src/dlmisc.c                | 41 +++++++++++++++++++++++++++++------
 src/rawmidi/rawmidi.c       | 43 ++++++++++++++++---------------------
 src/rawmidi/rawmidi_local.h |  2 +-
 4 files changed, 57 insertions(+), 32 deletions(-)

diff --git a/include/local.h b/include/local.h
index 5edad317..e8390df5 100644
--- a/include/local.h
+++ b/include/local.h
@@ -328,6 +328,8 @@ static inline int snd_open_device(const char *filename, int fmode)
 /* make local functions really local */
 #define snd_dlobj_cache_get \
 	snd1_dlobj_cache_get
+#define snd_dlobj_cache_get2 \
+	snd1_dlobj_cache_get2
 #define snd_dlobj_cache_put \
 	snd1_dlobj_cache_put
 #define snd_dlobj_cache_cleanup \
@@ -341,6 +343,7 @@ static inline int snd_open_device(const char *filename, int fmode)
 
 /* dlobj cache */
 void *snd_dlobj_cache_get(const char *lib, const char *name, const char *version, int verbose);
+void *snd_dlobj_cache_get2(const char *lib, const char *name, const char *version, int verbose);
 int snd_dlobj_cache_put(void *open_func);
 void snd_dlobj_cache_cleanup(void);
 
diff --git a/src/dlmisc.c b/src/dlmisc.c
index 012e61bc..8c8f3ff7 100644
--- a/src/dlmisc.c
+++ b/src/dlmisc.c
@@ -251,15 +251,15 @@ static inline void snd_dlobj_unlock(void) {}
 
 static LIST_HEAD(pcm_dlobj_list);
 
-void *snd_dlobj_cache_get(const char *lib, const char *name,
-			  const char *version, int verbose)
+static struct dlobj_cache *
+snd_dlobj_cache_get0(const char *lib, const char *name,
+		     const char *version, int verbose)
 {
 	struct list_head *p;
 	struct dlobj_cache *c;
 	void *func, *dlobj;
 	char errbuf[256];
 
-	snd_dlobj_lock();
 	list_for_each(p, &pcm_dlobj_list) {
 		c = list_entry(p, struct dlobj_cache, list);
 		if (c->lib && lib && strcmp(c->lib, lib) != 0)
@@ -270,9 +270,7 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 			continue;
 		if (strcmp(c->name, name) == 0) {
 			c->refcnt++;
-			func = c->func;
-			snd_dlobj_unlock();
-			return func;
+			return c;
 		}
 	}
 
@@ -285,7 +283,6 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 			SNDERR("Cannot open shared library %s (%s)",
 						lib ? lib : "[builtin]",
 						errbuf);
-		snd_dlobj_unlock();
 		return NULL;
 	}
 
@@ -314,6 +311,36 @@ void *snd_dlobj_cache_get(const char *lib, const char *name,
 	c->dlobj = dlobj;
 	c->func = func;
 	list_add_tail(&c->list, &pcm_dlobj_list);
+	return c;
+}
+
+void *snd_dlobj_cache_get(const char *lib, const char *name,
+			  const char *version, int verbose)
+{
+	struct dlobj_cache *c;
+	void *func = NULL;
+
+	snd_dlobj_lock();
+	c = snd_dlobj_cache_get0(lib, name, version, verbose);
+	if (c)
+		func = c->func;
+	snd_dlobj_unlock();
+	return func;
+}
+
+void *snd_dlobj_cache_get2(const char *lib, const char *name,
+			   const char *version, int verbose)
+{
+	struct dlobj_cache *c;
+	void *func = NULL;
+
+	snd_dlobj_lock();
+	c = snd_dlobj_cache_get0(lib, name, version, verbose);
+	if (c) {
+		func = c->func;
+		/* double reference */
+		c->refcnt++;
+	}
 	snd_dlobj_unlock();
 	return func;
 }
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index 2f419142..1b5f8525 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -162,7 +162,7 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 				 snd_config_t *rawmidi_conf, int mode)
 {
 	const char *str;
-	char buf[256], errbuf[256];
+	char buf[256];
 	int err;
 	snd_config_t *conf, *type_conf = NULL;
 	snd_config_iterator_t i, next;
@@ -174,7 +174,6 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 #ifndef PIC
 	extern void *snd_rawmidi_open_symbols(void);
 #endif
-	void *h = NULL;
 	if (snd_config_get_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
 		if (name)
 			SNDERR("Invalid type for RAWMIDI %s definition", name);
@@ -239,41 +238,37 @@ static int snd_rawmidi_open_conf(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp
 #ifndef PIC
 	snd_rawmidi_open_symbols();
 #endif
-	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
-	if (h)
-		open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION));
-	err = 0;
-	if (!h) {
-		SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
-		err = -ENOENT;
-	} else if (!open_func) {
-		SNDERR("symbol %s is not defined inside %s", open_name, lib);
-		snd_dlclose(h);
+	open_func = snd_dlobj_cache_get2(lib, open_name,
+			SND_DLSYM_VERSION(SND_RAWMIDI_DLSYM_VERSION), 1);
+	if (!open_func) {
 		err = -ENXIO;
+		goto _err;
 	}
-       _err:
 	if (type_conf)
 		snd_config_delete(type_conf);
-	if (err >= 0)
-		err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
-	if (err < 0) {
-		if (h)
-			snd_dlclose(h);
-		return err;
-	}
+	err = open_func(inputp, outputp, name, rawmidi_root, rawmidi_conf, mode);
+	if (err < 0)
+		goto _err;
 	if (inputp) {
-		(*inputp)->dl_handle = h; h = NULL;
+		(*inputp)->open_func = open_func;
 		snd_rawmidi_params_default(*inputp, &params);
 		err = snd_rawmidi_params(*inputp, &params);
 		assert(err >= 0);
 	}
 	if (outputp) {
-		(*outputp)->dl_handle = h;
+		(*outputp)->open_func = open_func;
 		snd_rawmidi_params_default(*outputp, &params);
 		err = snd_rawmidi_params(*outputp, &params);
 		assert(err >= 0);
 	}
 	return 0;
+
+       _err:
+	if (open_func)
+		snd_dlobj_cache_put(open_func);
+	if (type_conf)
+		snd_config_delete(type_conf);
+	return err;
 }
 
 static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
@@ -350,8 +345,8 @@ int snd_rawmidi_close(snd_rawmidi_t *rawmidi)
   	assert(rawmidi);
 	err = rawmidi->ops->close(rawmidi);
 	free(rawmidi->name);
-	if (rawmidi->dl_handle)
-		snd_dlclose(rawmidi->dl_handle);
+	if (rawmidi->open_func)
+		snd_dlobj_cache_put(rawmidi->open_func);
 	free(rawmidi);
 	return err;
 }
diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h
index d76b35a3..721e1ec9 100644
--- a/src/rawmidi/rawmidi_local.h
+++ b/src/rawmidi/rawmidi_local.h
@@ -37,7 +37,7 @@ typedef struct {
 } snd_rawmidi_ops_t;
 
 struct _snd_rawmidi {
-	void *dl_handle;
+	void *open_func;
 	char *name;
 	snd_rawmidi_type_t type;
 	snd_rawmidi_stream_t stream;
-- 
2.20.1


From 6efa23f2837a6fa9982b4f34b837401a66941ee3 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 20:45:26 +0200
Subject: [PATCH 19/25] rawmidi_hw: add sanity check for the invalid stream
 arguments (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/rawmidi/rawmidi_hw.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c
index 7cc8c0d1..eaa8a76d 100644
--- a/src/rawmidi/rawmidi_hw.c
+++ b/src/rawmidi/rawmidi_hw.c
@@ -186,6 +186,8 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
 		*inputp = NULL;
 	if (outputp)
 		*outputp = NULL;
+	if (!inputp && !outputp)
+		return -EINVAL;
 	
 	if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
 		return ret;
-- 
2.20.1


From 0d97f53c25b4dd36d3f6511fae85b597aebc61a1 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 20:52:00 +0200
Subject: [PATCH 20/25] topology: various coverity fixes

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/topology/ctl.c    |  4 ++--
 src/topology/data.c   | 19 +++++++++++++------
 src/topology/parser.c |  5 +++--
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/topology/ctl.c b/src/topology/ctl.c
index 9c13b12c..a0962522 100644
--- a/src/topology/ctl.c
+++ b/src/topology/ctl.c
@@ -880,8 +880,8 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
 	if (enum_ctl->texts != NULL) {
 		for (i = 0; i < num_items; i++) {
 			if (enum_ctl->texts[i] != NULL)
-				strncpy(ec->texts[i], enum_ctl->texts[i],
-					SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+				snd_strlcpy(ec->texts[i], enum_ctl->texts[i],
+					    SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
 		}
 	}
 
diff --git a/src/topology/data.c b/src/topology/data.c
index fd72abbb..aa2b87e7 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -124,12 +124,12 @@ static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
 
 	if (fclose(fp) == EOF) {
 		SNDERR("Cannot close data file.");
-		ret = -errno;
-		goto err;
+		return -errno;
 	}
 	return 0;
 
 err:
+	fclose(fp);
 	if (priv)
 		free(priv);
 	return ret;
@@ -422,7 +422,7 @@ static unsigned int get_tuple_size(int type)
 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 snd_soc_tplg_private *priv = elem->data, *priv2;
 	struct tplg_tuple_set *tuple_set;
 	struct tplg_tuple *tuple;
 	struct snd_soc_tplg_vendor_array *array;
@@ -447,10 +447,17 @@ static int copy_tuples(struct tplg_elem *elem,
 			return -EINVAL;
 		}
 
-		if (priv != NULL)
-			priv = realloc(priv, sizeof(*priv) + size);
-		else
+		if (priv != NULL) {
+			priv2 = realloc(priv, sizeof(*priv) + size);
+			if (priv2 == NULL) {
+				free(priv);
+				priv = NULL;
+			} else {
+				priv = priv2;
+			}
+		} else {
 			priv = calloc(1, sizeof(*priv) + size);
+		}
 		if (!priv)
 			return -ENOMEM;
 
diff --git a/src/topology/parser.c b/src/topology/parser.c
index cfc20e00..a7cff1c3 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -237,8 +237,9 @@ static int tplg_load_config(const char *file, snd_config_t **cfg)
 
 	ret = snd_input_stdio_attach(&in, fp, 1);
 	if (ret < 0) {
+		fclose(fp);
 		SNDERR("error: could not attach stdio %s", file);
-		goto err;
+		return ret;
 	}
 	ret = snd_config_top(&top);
 	if (ret < 0)
@@ -261,7 +262,7 @@ static int tplg_load_config(const char *file, snd_config_t **cfg)
 err_load:
 	snd_config_delete(top);
 err:
-	fclose(fp);
+	snd_input_close(in);
 	return ret;
 }
 
-- 
2.20.1


From ed156a218644e3334bc452ef2bc948409735c330 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Fri, 24 May 2019 21:11:00 +0200
Subject: [PATCH 21/25] ucm: coverity fixes

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/ucm/parser.c | 18 ++++++++++++++----
 src/ucm/utils.c  | 12 +++++++++---
 2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/ucm/parser.c b/src/ucm/parser.c
index ad6bcec7..61d5d7f9 100644
--- a/src/ucm/parser.c
+++ b/src/ucm/parser.c
@@ -1114,7 +1114,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
 			if (err < 0) {
 				uc_error("error: %s failed to parse verb",
 						file);
-				return err;
+				goto _err;
 			}
 			continue;
 		}
@@ -1126,7 +1126,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
 			if (err < 0) {
 				uc_error("error: %s failed to parse device",
 						file);
-				return err;
+				goto _err;
 			}
 			continue;
 		}
@@ -1138,18 +1138,24 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
 			if (err < 0) {
 				uc_error("error: %s failed to parse modifier",
 						file);
-				return err;
+				goto _err;
 			}
 			continue;
 		}
 	}
 
+	snd_config_delete(cfg);
+
 	/* use case verb must have at least 1 device */
 	if (list_empty(&verb->device_list)) {
 		uc_error("error: no use case device defined", file);
 		return -EINVAL;
 	}
 	return 0;
+
+       _err:
+	snd_config_delete(cfg);
+	return err;
 }
 
 /*
@@ -1399,6 +1405,7 @@ next_card:
 
 	return -1;
 }
+
 static int load_master_config(const char *card_name, snd_config_t **cfg)
 {
 	char filename[MAX_FILE];
@@ -1610,8 +1617,11 @@ int uc_mgr_scan_master_configs(const char **_list[])
 	}
 	free(namelist);
 
-	if (err >= 0)
+	if (err >= 0) {
 		*_list = list;
+	} else {
+		free(list);
+	}
 
 	return err;
 }
diff --git a/src/ucm/utils.c b/src/ucm/utils.c
index 14227e0a..efd5a979 100644
--- a/src/ucm/utils.c
+++ b/src/ucm/utils.c
@@ -58,14 +58,18 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
 	int err;
 
 	fp = fopen(file, "r");
-	err = fp == NULL ? -errno : snd_input_stdio_attach(&in, fp, 1);
-	if (err < 0) {
+	if (!fp) {
+		err = -errno;
+  __err0:
 		uc_error("could not open configuration file %s", file);
 		return err;
 	}
+	err = snd_input_stdio_attach(&in, fp, 1);
+	if (err < 0)
+		goto __err0;
 	err = snd_config_top(&top);
 	if (err < 0)
-		return err;
+		goto __err1;
 
 	default_path = getenv(ALSA_CONFIG_UCM_VAR);
 	if (!default_path || !*default_path)
@@ -88,6 +92,8 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
 
  __err2:
         snd_config_delete(top);
+ __err1:
+	snd_input_close(in);
 	return err;
 }
 
-- 
2.20.1


From 022c790aabc300eabad4da8947a3f2bdadce41e1 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Mon, 27 May 2019 13:57:12 +0200
Subject: [PATCH 22/25] pcm_file: coverity fixes (including double locking)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_file.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 99db3754..54142a3d 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -296,7 +296,10 @@ static int snd_pcm_file_areas_read_infile(snd_pcm_t *pcm,
 		return -ENOMEM;
 	}
 
-	bytes = read(file->ifd, file->rbuf, snd_pcm_frames_to_bytes(pcm, frames));
+	bytes = snd_pcm_frames_to_bytes(pcm, frames);
+	if (bytes < 0)
+		return bytes;
+	bytes = read(file->ifd, file->rbuf, bytes);
 	if (bytes < 0) {
 		SYSERR("read from file failed, error: %d", bytes);
 		return bytes;
@@ -589,18 +592,14 @@ static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pc
 	snd_pcm_channel_area_t areas[pcm->channels];
 	snd_pcm_sframes_t frames;
 
-	__snd_pcm_lock(pcm);
-
 	frames = _snd_pcm_readi(file->gen.slave, buffer, size);
-	if (frames <= 0) {
-		__snd_pcm_unlock(pcm);
+	if (frames <= 0)
 		return frames;
-	}
 
 	snd_pcm_areas_from_buf(pcm, areas, buffer);
 	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
+	__snd_pcm_lock(pcm);
 	snd_pcm_file_add_frames(pcm, areas, 0, frames);
-
 	__snd_pcm_unlock(pcm);
 
 	return frames;
@@ -654,9 +653,6 @@ static int snd_pcm_file_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t
 	snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
 {
 	snd_pcm_file_t *file = pcm->private_data;
-	snd_pcm_channel_area_t areas_if[pcm->channels];
-	snd_pcm_uframes_t frames_if;
-	void *buffer = NULL;
 	int result;
 
 	result = snd_pcm_mmap_begin(file->gen.slave, areas, offset, frames);
-- 
2.20.1


From c6e7fd8b1e0d8729c7220734ca0b529c35d926ed Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Mon, 27 May 2019 14:05:12 +0200
Subject: [PATCH 23/25] topology: next round of coverity fixes

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/topology/data.c   | 5 ++---
 src/topology/parser.c | 7 +++++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/topology/data.c b/src/topology/data.c
index aa2b87e7..b3f4421f 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -88,8 +88,7 @@ static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
 	if (fp == NULL) {
 		SNDERR("error: invalid data file path '%s'\n",
 			filename);
-		ret = -errno;
-		goto err;
+		return -errno;
 	}
 
 	fseek(fp, 0L, SEEK_END);
@@ -463,6 +462,7 @@ static int copy_tuples(struct tplg_elem *elem,
 
 		off = priv->size;
 		priv->size = size; /* update private data size */
+		elem->data = priv;
 
 		array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
 		array->size = set_size;
@@ -499,7 +499,6 @@ static int copy_tuples(struct tplg_elem *elem,
 		}
 	}
 
-	elem->data = priv;
 	return 0;
 }
 
diff --git a/src/topology/parser.c b/src/topology/parser.c
index a7cff1c3..5940692d 100644
--- a/src/topology/parser.c
+++ b/src/topology/parser.c
@@ -253,8 +253,10 @@ static int tplg_load_config(const char *file, snd_config_t **cfg)
 	}
 
 	ret = snd_input_close(in);
-	if (ret < 0)
+	if (ret < 0) {
+		in = NULL;
 		goto err_load;
+	}
 
 	*cfg = top;
 	return 0;
@@ -262,7 +264,8 @@ static int tplg_load_config(const char *file, snd_config_t **cfg)
 err_load:
 	snd_config_delete(top);
 err:
-	snd_input_close(in);
+	if (in)
+		snd_input_close(in);
 	return ret;
 }
 
-- 
2.20.1


From ac6df1106c314de5d027176d910b9bc43a1fa7f9 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Mon, 27 May 2019 20:10:32 +0200
Subject: [PATCH 24/25] pcm_file: another locking fix (coverity)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_file.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 54142a3d..1ef80b59 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -612,18 +612,16 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm
 	snd_pcm_channel_area_t areas[pcm->channels];
 	snd_pcm_sframes_t frames;
 
-	__snd_pcm_lock(pcm);
 	frames = _snd_pcm_readn(file->gen.slave, bufs, size);
-	if (frames <= 0) {
-		__snd_pcm_unlock(pcm);
+	if (frames <= 0)
 		return frames;
-	}
 
 	snd_pcm_areas_from_bufs(pcm, areas, bufs);
 	snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
+	__snd_pcm_lock(pcm);
 	snd_pcm_file_add_frames(pcm, areas, 0, frames);
-
 	__snd_pcm_unlock(pcm);
+
 	return frames;
 }
 
-- 
2.20.1


From 5905af199670ca34eaaafbd3319d94d230b7e4d4 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Mon, 27 May 2019 20:10:52 +0200
Subject: [PATCH 25/25] ucm: another coverity fix in uc_mgr_config_load()

---
 src/ucm/utils.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/ucm/utils.c b/src/ucm/utils.c
index efd5a979..5607304e 100644
--- a/src/ucm/utils.c
+++ b/src/ucm/utils.c
@@ -85,15 +85,18 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
 		goto __err2;
 	}
 	err = snd_input_close(in);
-	if (err < 0)
+	if (err < 0) {
+		in = NULL;
 		goto __err2;
+	}
 	*cfg = top;
 	return 0;
 
  __err2:
-        snd_config_delete(top);
+	snd_config_delete(top);
  __err1:
-	snd_input_close(in);
+	if (in)
+		snd_input_close(in);
 	return err;
 }
 
-- 
2.20.1