Blob Blame History Raw
From 7a748af4db17cb0b26d19e5f9939d277128ec94b Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
Date: Thu, 26 Jun 2014 13:30:25 +0300
Subject: [PATCH 01/35] ucm: Document PlaybackPCMIsDummy and CapturePCMIsDummy
 values

At least PulseAudio needs special handling for dummy devices. To allow
that to happen automatically, the UCM configuration should contain the
information about which PCMs are dummy.

Signed-off-by: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/use-case.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/use-case.h b/include/use-case.h
index 4e13249..f30168f 100644
--- a/include/use-case.h
+++ b/include/use-case.h
@@ -258,7 +258,17 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
  * Recommended names for values:
  *   TQ			- Tone Quality
  *   PlaybackPCM	- full PCM playback device name
+ *   PlaybackPCMIsDummy	- Valid values: "yes" and "no". If set to "yes", the
+ *			  PCM named by the PlaybackPCM value is a dummy device,
+ *			  meaning that opening it enables an audio path in the
+ *			  hardware, but writing to the PCM device has no
+ *			  effect.
  *   CapturePCM		- full PCM capture device name
+ *   CapturePCMIsDummy	- Valid values: "yes" and "no". If set to "yes", the
+ *			  PCM named by the CapturePCM value is a dummy device,
+ *			  meaning that opening it enables an audio path in the
+ *			  hardware, but reading from the PCM device has no
+ *			  effect.
  *   PlaybackRate	- playback device sample rate
  *   PlaybackChannels	- playback device channel count
  *   PlaybackCTL	- playback control device name
-- 
1.9.3


From 27cc710b5784cb3ab68cff2a9d9daf9fa479149e Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Tue, 1 Jul 2014 00:40:48 +0600
Subject: [PATCH 02/35] ICE1712: add surround71 pcm definition

The M-Audio Delta 1010 card has 7.1 analog output, but no ready-made pcm
definition to use it.

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Reported-and-tested-by: Matt Zagrabelny <mzagrabe@d.umn.edu>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/conf/cards/ICE1712.conf | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/conf/cards/ICE1712.conf b/src/conf/cards/ICE1712.conf
index 398fa7a..db62684 100644
--- a/src/conf/cards/ICE1712.conf
+++ b/src/conf/cards/ICE1712.conf
@@ -78,6 +78,7 @@ ICE1712.pcm.surround40.0 {
 <confdir:pcm/surround41.conf>
 <confdir:pcm/surround50.conf>
 <confdir:pcm/surround51.conf>
+<confdir:pcm/surround71.conf>
 
 ICE1712.pcm.surround51.0 {
 	@args [ CARD ]
@@ -98,6 +99,27 @@ ICE1712.pcm.surround51.0 {
 	slave.channels 10
 }
 
+ICE1712.pcm.surround71.0 {
+	@args [ CARD ]
+	@args.CARD {
+		type string
+	}
+	type route
+	ttable.0.0 1
+	ttable.1.1 1
+	ttable.2.2 1
+	ttable.3.3 1
+	ttable.4.4 1
+	ttable.5.5 1
+	ttable.6.6 1
+	ttable.7.7 1
+	slave.pcm {
+		type hw
+		card $CARD
+	}
+	slave.channels 10
+}
+
 <confdir:pcm/iec958.conf>
 
 ICE1712.pcm.iec958.0 {
-- 
1.9.3


From ea865bba4615d906144ae5d4f72a4aad2baffe1f Mon Sep 17 00:00:00 2001
From: Anssi Hannula <anssi.hannula@iki.fi>
Date: Tue, 8 Jul 2014 11:19:20 +0300
Subject: [PATCH 03/35] USB-Audio: Add second S/PDIF device on Phiree U2

Phiree U2 has an unusual configuration. It only has S/PDIF output, but
there are still two devices presented:
- device 0: PCM audio, subject to volume control
- device 1: non-PCM data (passthrough), not subject to volume control

It looks like the AES bits are set according to the selected device,
since outputting PCM data via device 1 will not work (silence).

Currently only the device 0 is shown via the "iec958" alias, and the
second device is not accessible via hinted aliases.

Simply provide access to both of these devices via the "iec958" alias.

Reported-by: touc @ XBMC forum
Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/conf/cards/USB-Audio.conf | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf
index ce3ae01..77a48b9 100644
--- a/src/conf/cards/USB-Audio.conf
+++ b/src/conf/cards/USB-Audio.conf
@@ -52,6 +52,11 @@ USB-Audio.pcm.iec958_device {
 	"USB Device 0x46d:0x992" 999
 }
 
+# Second iec958 device number, if any.
+USB-Audio.pcm.iec958_2_device {
+	"PHIREE U2" 1  # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF
+}
+
 
 # If a device requires non-standard definitions for front, surround40,
 # surround51, surround71 or iec958, they can be defined here.
@@ -422,4 +427,39 @@ USB-Audio.pcm.iec958.0 {
 	}
 }
 
+USB-Audio.pcm.iec958.1 {
+	@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 }
+	@func refer
+	name {
+		@func concat
+		strings [
+			"cards.USB-Audio."
+			{ @func card_name card $CARD }
+			".pcm.iec958_2:CARD=" $CARD
+			",AES0=" $AES0 ",AES1=" $AES1 ",AES2=" $AES2 ",AES3=" $AES3
+		]
+	}
+	default {
+		# FIXME: we cannot set the AES parameters
+		type hw
+		card $CARD
+		device {
+			@func refer
+			name {
+				@func concat
+				strings [
+					"cards.USB-Audio.pcm.iec958_2_device."
+					{ @func card_name card $CARD }
+				]
+			}
+			default 999
+		}
+	}
+}
+
 # vim: ft=alsaconf
-- 
1.9.3


From 035f196bcdc1e9903ed52ad1859dc23d3aa74e72 Mon Sep 17 00:00:00 2001
From: Shengjiu Wang <shengjiu.wang@freescale.com>
Date: Mon, 14 Jul 2014 16:55:48 +0800
Subject: [PATCH 04/35] pcm: rate: fix hw_ptr exceed the boundary

For long time test case, the hw_ptr will exceed the boundary, then cause
the avail size wrong.

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

diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 7f667d4..2563d82 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -574,6 +574,8 @@ static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm)
 	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 %= pcm->boundary;
 }
 
 static int snd_pcm_rate_hwsync(snd_pcm_t *pcm)
-- 
1.9.3


From 85e4704151677b8fcc5ccfc396071828e9ec1b8e Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@linaro.org>
Date: Tue, 8 Jul 2014 16:52:32 +0200
Subject: [PATCH 05/35] pcm: Provide a CLOCK_MONOTONIC_RAW timestamp type

For applications which need to synchronise with external timebases such
as broadcast TV applications the kernel monotonic time is not optimal as
it includes adjustments from NTP and so may still include discontinuities
due to that. A raw monotonic time which does not include any adjustments
is available in the kernel from getrawmonotonic() so provide userspace with
a new timestamp type SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW which provides
timestamps based on this as an option.

Reported-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asound.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 1774a5c..9061cdd 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -457,7 +457,8 @@ struct snd_xfern {
 enum {
 	SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,	/* gettimeofday equivalent */
 	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,	/* posix_clock_monotonic equivalent */
-	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW,	/* monotonic_raw (no NTP) */
+	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
 };
 
 /* channel positions */
-- 
1.9.3


From 5250a8e212fd927735cfc27612b060c31dc3a230 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 10 Jul 2014 14:22:33 +0200
Subject: [PATCH 06/35] Add timestamp type to sw_params (internal only)

This patch is just the udpate of sound/asound.h taken from the kernel
commit.  The API changes and PCM structure changes will follow after
this.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asound.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 9061cdd..552f41b 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -136,7 +136,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 11)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 12)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -386,7 +386,9 @@ struct snd_pcm_sw_params {
 	snd_pcm_uframes_t silence_threshold;	/* min distance from noise for silence filling */
 	snd_pcm_uframes_t silence_size;		/* silence block size */
 	snd_pcm_uframes_t boundary;		/* pointers wrap point */
-	unsigned char reserved[64];		/* reserved for future */
+	unsigned int tstamp_type;		/* timestamp type */
+	int pads;				/* alignment, reserved */
+	unsigned char reserved[56];		/* reserved for future */
 };
 
 struct snd_pcm_channel_info {
-- 
1.9.3


From 0d393c29a272b6fc97e9fca3252fb1c58f86e75b Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 10 Jul 2014 14:26:37 +0200
Subject: [PATCH 07/35] pcm: Add sw_params API functions to get/set timestamp
 type

For obtaining / changing the timestamp type, add the corresponding
sw_params accessor API functions together with the public definitions
of timestamp types.

This patch only adds the functions and defines but doesn't bring the
functional changes yet.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/pcm.h        |  9 +++++++++
 src/pcm/pcm.c        | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/pcm/pcm_local.h  |  1 +
 src/pcm/pcm_params.c |  1 +
 4 files changed, 64 insertions(+)

diff --git a/include/pcm.h b/include/pcm.h
index 95b8aed..11e9f0d 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -317,6 +317,13 @@ typedef enum _snd_pcm_tstamp {
 	SND_PCM_TSTAMP_LAST = SND_PCM_TSTAMP_ENABLE
 } snd_pcm_tstamp_t;
 
+typedef enum _snd_pcm_tstamp_type {
+	SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,	/** gettimeofday equivalent */
+	SND_PCM_TSTAMP_TYPE_MONOTONIC,	/** posix_clock_monotonic equivalent */
+	SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,	/** monotonic_raw (no NTP) */
+	SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
+} snd_pcm_tstamp_type_t;
+
 /** Unsigned frames quantity */
 typedef unsigned long snd_pcm_uframes_t;
 /** Signed frames quantity */
@@ -844,6 +851,8 @@ int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uf
 
 int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val);
 int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val);
+int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val);
+int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val);
 int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
 int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val);
 int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val);
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 7e46014..8984443 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -1483,6 +1483,7 @@ int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsign
 #define XRUN(v) [SND_PCM_XRUN_##v] = #v
 #define SILENCE(v) [SND_PCM_SILENCE_##v] = #v
 #define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v
+#define TSTAMP_TYPE(v) [SND_PCM_TSTAMP_TYPE_##v] = #v
 #define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
 #define START(v) [SND_PCM_START_##v] = #v
 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
@@ -1680,6 +1681,12 @@ static const char *const snd_pcm_tstamp_mode_names[] = {
 	TSTAMP(NONE),
 	TSTAMP(ENABLE),
 };
+
+static const char *const snd_pcm_tstamp_type_names[] = {
+	TSTAMP_TYPE(GETTIMEOFDAY),
+	TSTAMP_TYPE(MONOTONIC),
+	TSTAMP_TYPE(MONOTONIC_RAW),
+};
 #endif
 
 /**
@@ -1826,6 +1833,18 @@ const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode)
 }
 
 /**
+ * \brief get name of PCM tstamp type setting
+ * \param mode PCM tstamp type
+ * \return ascii name of PCM tstamp type setting
+ */
+const char *snd_pcm_tstamp_type_name(snd_pcm_tstamp_t type)
+{
+	if (type > SND_PCM_TSTAMP_TYPE_LAST)
+		return NULL;
+	return snd_pcm_tstamp_type_names[type];
+}
+
+/**
  * \brief get name of PCM state
  * \param state PCM state
  * \return ascii name of PCM state
@@ -1899,6 +1918,7 @@ int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out)
 		return -EIO;
 	}
 	snd_output_printf(out, "  tstamp_mode  : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode));
+	snd_output_printf(out, "  tstamp_type  : %s\n", snd_pcm_tstamp_type_name(pcm->tstamp_mode));
 	snd_output_printf(out, "  period_step  : %d\n", pcm->period_step);
 	snd_output_printf(out, "  avail_min    : %ld\n", pcm->avail_min);
 	snd_output_printf(out, "  period_event : %i\n", pcm->period_event);
@@ -5591,6 +5611,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 		return -EIO;
 	}
 	params->tstamp_mode = pcm->tstamp_mode;
+	params->tstamp_type = pcm->tstamp_type;
 	params->period_step = pcm->period_step;
 	params->sleep_min = 0;
 	params->avail_min = pcm->avail_min;
@@ -5613,6 +5634,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out)
 {
 	snd_output_printf(out, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(params->tstamp_mode));
+	snd_output_printf(out, "tstamp_type: %s\n", snd_pcm_tstamp_type_name(params->tstamp_type));
 	snd_output_printf(out, "period_step: %u\n", params->period_step);
 	snd_output_printf(out, "avail_min: %lu\n", params->avail_min);
 	snd_output_printf(out, "start_threshold: %ld\n", params->start_threshold);
@@ -5811,6 +5833,37 @@ int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm
 }
 
 /**
+ * \brief Set timestamp type inside a software configuration container
+ * \param pcm PCM handle
+ * \param params Software configuration container
+ * \param val Timestamp type
+ * \return 0 otherwise a negative error code
+ */
+int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val)
+{
+	assert(pcm && params);
+	if (CHECK_SANITY(val > SND_PCM_TSTAMP_TYPE_LAST)) {
+		SNDMSG("invalid tstamp_type value %d", val);
+		return -EINVAL;
+	}
+	params->tstamp_type = val;
+	return 0;
+}
+
+/**
+ * \brief Get timestamp type from a software configuration container
+ * \param params Software configuration container
+ * \param val Returned timestamp type
+ * \return 0 otherwise a negative error code
+ */
+int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val)
+{
+	assert(params && val);
+	*val = params->tstamp_type;
+	return 0;
+}
+
+/**
  * \brief (DEPRECATED) Set minimum number of ticks to sleep inside a software configuration container
  * \param pcm PCM handle
  * \param params Software configuration container
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 8a6c743..3ed7e1a 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -202,6 +202,7 @@ struct _snd_pcm {
 	unsigned int period_time;	/* period duration */
 	snd_interval_t periods;
 	snd_pcm_tstamp_t tstamp_mode;	/* timestamp mode */
+	snd_pcm_tstamp_type_t tstamp_type;	/* timestamp type */
 	unsigned int period_step;
 	snd_pcm_uframes_t avail_min;	/* min avail frames for wakeup */
 	int period_event;
diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c
index 0b66e8c..4adbefa 100644
--- a/src/pcm/pcm_params.c
+++ b/src/pcm/pcm_params.c
@@ -2258,6 +2258,7 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params
 	assert(pcm && params);
 	assert(pcm->setup);
 	params->tstamp_mode = SND_PCM_TSTAMP_NONE;
+	params->tstamp_type = pcm->tstamp_type;
 	params->period_step = 1;
 	params->sleep_min = 0;
 	params->avail_min = pcm->period_size;
-- 
1.9.3


From 9b716075de4f2f7f15e428ee7efaa8960ef45b9c Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 10 Jul 2014 14:32:50 +0200
Subject: [PATCH 08/35] pcm: Implement timestamp type setup in hw plugin

This patch implements the support for sw_params timestamp type in PCM
hw layer.  As gettimestamp() is still unchanged, the resultant
timstamps may be still with CLOCK_MONOTONIC even if you pass monotonic
raw type.  More fixes will follow.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_hw.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index ed83197..bafa8de 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -304,7 +304,8 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 
 	if (params->info != ~0U) {
 		params->info &= ~0xf0000000;
-		params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
+		if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
+			params->info |= SND_PCM_INFO_MONOTONIC;
 	}
 	
 	return 0;
@@ -328,7 +329,8 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 		return err;
 	}
 	params->info &= ~0xf0000000;
-	params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
+	if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY)
+		params->info |= SND_PCM_INFO_MONOTONIC;
 	err = sync_ptr(hw, 0);
 	if (err < 0)
 		return err;
@@ -435,6 +437,7 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 	int old_period_event = sw_get_period_event(params);
 	sw_set_period_event(params, 0);
 	if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
+	    (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type &&
 	    params->period_step == pcm->period_step &&
 	    params->start_threshold == pcm->start_threshold &&
 	    params->stop_threshold == pcm->stop_threshold &&
@@ -444,11 +447,33 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 		hw->mmap_control->avail_min = params->avail_min;
 		return sync_ptr(hw, 0);
 	}
+	if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW &&
+	    hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
+		SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW");
+		return -EINVAL;
+	}
+	if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC &&
+	    hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
+		SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC");
+		return -EINVAL;
+	}
 	if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
 		err = -errno;
 		SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err);
 		return err;
 	}
+	if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) {
+		if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) {
+			int on = (snd_pcm_tstamp_type_t) params->tstamp_type ==
+				SND_PCM_TSTAMP_TYPE_MONOTONIC;
+			if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) {
+				err = -errno;
+				SNDMSG("TSTAMP failed\n");
+				return err;
+			}
+		}
+		pcm->tstamp_type = params->tstamp_type;
+	}
 	sw_set_period_event(params, old_period_event);
 	hw->mmap_control->avail_min = params->avail_min;
 	if (hw->period_event != old_period_event) {
@@ -1381,7 +1406,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
 		       int fd, int mmap_emulation ATTRIBUTE_UNUSED,
 		       int sync_ptr_ioctl)
 {
-	int ver, mode, monotonic = 0;
+	int ver, mode;
+	snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
 	long fmode;
 	snd_pcm_t *pcm = NULL;
 	snd_pcm_hw_t *hw = NULL;
@@ -1429,7 +1455,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
 				SNDMSG("TTSTAMP failed\n");
 				return ret;
 			}
-			monotonic = 1;
+			tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
 		}
 	} else
 #endif
@@ -1471,7 +1497,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
 	pcm->private_data = hw;
 	pcm->poll_fd = fd;
 	pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
-	pcm->monotonic = monotonic;
+	pcm->tstamp_type = tstamp_type;
+	pcm->monotonic = tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
 
 	ret = snd_pcm_hw_mmap_status(pcm);
 	if (ret < 0) {
-- 
1.9.3


From 65ff6fdafb705b5e2e6d4b9a94a80e5de89f5de1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 10 Jul 2014 14:37:49 +0200
Subject: [PATCH 09/35] pcm: Implement timestamp type handling in all plugins

Now all PCM plugins do support the proper timestamp type or pass it
over slaves.  The internal monotonic flag is dropped and replaced with
tstamp_type in all places.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_adpcm.c     |  2 +-
 src/pcm/pcm_alaw.c      |  2 +-
 src/pcm/pcm_copy.c      |  2 +-
 src/pcm/pcm_direct.c    |  4 ++--
 src/pcm/pcm_direct.h    |  2 +-
 src/pcm/pcm_dmix.c      |  8 ++++----
 src/pcm/pcm_dshare.c    |  8 ++++----
 src/pcm/pcm_dsnoop.c    |  4 ++--
 src/pcm/pcm_file.c      |  6 +++---
 src/pcm/pcm_generic.c   |  2 +-
 src/pcm/pcm_hooks.c     |  2 +-
 src/pcm/pcm_hw.c        |  1 -
 src/pcm/pcm_iec958.c    |  2 +-
 src/pcm/pcm_ioplug.c    |  9 ++++++---
 src/pcm/pcm_ladspa.c    |  2 +-
 src/pcm/pcm_lfloat.c    |  2 +-
 src/pcm/pcm_linear.c    |  2 +-
 src/pcm/pcm_local.h     | 45 +++++++++++++++++++++++++++++----------------
 src/pcm/pcm_meter.c     |  2 +-
 src/pcm/pcm_mmap_emul.c |  2 +-
 src/pcm/pcm_mulaw.c     |  2 +-
 src/pcm/pcm_multi.c     |  2 +-
 src/pcm/pcm_null.c      |  2 +-
 src/pcm/pcm_plug.c      |  2 +-
 src/pcm/pcm_rate.c      |  4 ++--
 src/pcm/pcm_route.c     |  2 +-
 src/pcm/pcm_share.c     |  6 +++---
 src/pcm/pcm_softvol.c   |  2 +-
 28 files changed, 73 insertions(+), 58 deletions(-)

diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c
index 6f0e7c4..1a83c5a 100644
--- a/src/pcm/pcm_adpcm.c
+++ b/src/pcm/pcm_adpcm.c
@@ -579,7 +579,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
 	pcm->private_data = adpcm;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c
index 1b1bab8..db759e3 100644
--- a/src/pcm/pcm_alaw.c
+++ b/src/pcm/pcm_alaw.c
@@ -453,7 +453,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
 	pcm->private_data = alaw;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c
index 56a1f6b..66d3a47 100644
--- a/src/pcm/pcm_copy.c
+++ b/src/pcm/pcm_copy.c
@@ -209,7 +209,7 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
 	pcm->private_data = copy;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &copy->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &copy->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c
index 5416cf7..8e37bcb 100644
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -840,6 +840,7 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 	COPY_SLAVE(period_time);
 	COPY_SLAVE(periods);
 	COPY_SLAVE(tstamp_mode);
+	COPY_SLAVE(tstamp_type);
 	COPY_SLAVE(period_step);
 	COPY_SLAVE(avail_min);
 	COPY_SLAVE(start_threshold);
@@ -857,7 +858,6 @@ 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);
-	COPY_SLAVE(monotonic);
 }
 
 #undef COPY_SLAVE
@@ -1204,6 +1204,7 @@ static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 	COPY_SLAVE(period_time);
 	COPY_SLAVE(periods);
 	COPY_SLAVE(tstamp_mode);
+	COPY_SLAVE(tstamp_type);
 	COPY_SLAVE(period_step);
 	COPY_SLAVE(avail_min);
 	COPY_SLAVE(start_threshold);
@@ -1221,7 +1222,6 @@ static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm)
 	COPY_SLAVE(buffer_time);
 	COPY_SLAVE(sample_bits);
 	COPY_SLAVE(frame_bits);
-	COPY_SLAVE(monotonic);
 
 	spcm->info &= ~SND_PCM_INFO_PAUSE;
 	spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size);
diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h
index 5ae39c0..9b1ddbc 100644
--- a/src/pcm/pcm_direct.h
+++ b/src/pcm/pcm_direct.h
@@ -85,8 +85,8 @@ typedef struct {
 		unsigned int period_size;
 		unsigned int period_time;
 		snd_interval_t periods;
-		unsigned int monotonic;
 		snd_pcm_tstamp_t tstamp_mode;
+		snd_pcm_tstamp_type_t tstamp_type;
 		unsigned int period_step;
 		unsigned int sleep_min; /* not used */
 		unsigned int avail_min;
diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index 4aa6d4e..7c53509 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -428,7 +428,7 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
 		dmix->avail_max = avail;
 	if (avail >= pcm->stop_threshold) {
 		snd_timer_stop(dmix->timer);
-		gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
+		gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
 		if (dmix->state == SND_PCM_STATE_RUNNING) {
 			dmix->state = SND_PCM_STATE_XRUN;
 			return -EPIPE;
@@ -477,7 +477,7 @@ static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 	memset(status, 0, sizeof(*status));
 	status->state = snd_pcm_dmix_state(pcm);
 	status->trigger_tstamp = dmix->trigger_tstamp;
-	gettimestamp(&status->tstamp, pcm->monotonic);
+	gettimestamp(&status->tstamp, pcm->tstamp_type);
 	status->avail = snd_pcm_mmap_playback_avail(pcm);
 	status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
 	dmix->avail_max = 0;
@@ -596,7 +596,7 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm)
 			return err;
 		snd_pcm_dmix_sync_area(pcm);
 	}
-	gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
 	return 0;
 }
 
@@ -1104,7 +1104,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 		
 	pcm->poll_fd = dmix->poll_fd;
 	pcm->poll_events = POLLIN;	/* it's different than other plugins */
-	pcm->monotonic = spcm->monotonic;
+	pcm->tstamp_type = spcm->tstamp_type;
 	pcm->mmap_rw = 1;
 	snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index f2d1103..b985172 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -195,7 +195,7 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
 		dshare->avail_max = avail;
 	if (avail >= pcm->stop_threshold) {
 		snd_timer_stop(dshare->timer);
-		gettimestamp(&dshare->trigger_tstamp, pcm->monotonic);
+		gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
 		if (dshare->state == SND_PCM_STATE_RUNNING) {
 			dshare->state = SND_PCM_STATE_XRUN;
 			return -EPIPE;
@@ -226,7 +226,7 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 	memset(status, 0, sizeof(*status));
 	status->state = snd_pcm_state(dshare->spcm);
 	status->trigger_tstamp = dshare->trigger_tstamp;
-	gettimestamp(&status->tstamp, pcm->monotonic);
+	gettimestamp(&status->tstamp, pcm->tstamp_type);
 	status->avail = snd_pcm_mmap_playback_avail(pcm);
 	status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
 	dshare->avail_max = 0;
@@ -346,7 +346,7 @@ static int snd_pcm_dshare_start(snd_pcm_t *pcm)
 			return err;
 		snd_pcm_dshare_sync_area(pcm);
 	}
-	gettimestamp(&dshare->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
 	return 0;
 }
 
@@ -792,7 +792,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 
 	pcm->poll_fd = dshare->poll_fd;
 	pcm->poll_events = POLLIN;	/* it's different than other plugins */
-	pcm->monotonic = spcm->monotonic;
+	pcm->tstamp_type = spcm->tstamp_type;
 	pcm->mmap_rw = 1;
 	snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0);
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index 7637914..0f9c9df 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -159,7 +159,7 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
 	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
 		return 0;
 	if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
-		gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic);
+		gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type);
 		dsnoop->state = SND_PCM_STATE_XRUN;
 		dsnoop->avail_max = avail;
 		return -EPIPE;
@@ -690,7 +690,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 
 	pcm->poll_fd = dsnoop->poll_fd;
 	pcm->poll_events = POLLIN;	/* it's different than other plugins */
-	pcm->monotonic = spcm->monotonic;
+	pcm->tstamp_type = spcm->tstamp_type;
 	pcm->mmap_rw = 1;
 	snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index b139f7f..a0b8bf4 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -781,10 +781,10 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
 	pcm->mmap_shadow = 1;
+	pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-	pcm->monotonic = clock_gettime(CLOCK_MONOTONIC, &timespec) == 0;
-#else
-	pcm->monotonic = 0;
+	if (clock_gettime(CLOCK_MONOTONIC, &timespec) == 0)
+		pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
 #endif
 	pcm->stream = stream;
 	snd_pcm_link_hw_ptr(pcm, slave);
diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c
index f068ee2..9b60591 100644
--- a/src/pcm/pcm_generic.c
+++ b/src/pcm/pcm_generic.c
@@ -294,7 +294,7 @@ int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
 		if (ok && (snd_pcm_uframes_t)avail1 == *avail)
 			break;
 		*avail = avail1;
-		gettimestamp(tstamp, pcm->monotonic);
+		gettimestamp(tstamp, pcm->tstamp_type);
 		ok = 1;
 	}
 	return 0;
diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c
index f837282..0b93c64 100644
--- a/src/pcm/pcm_hooks.c
+++ b/src/pcm/pcm_hooks.c
@@ -240,7 +240,7 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
 	pcm->mmap_shadow = 1;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index bafa8de..74cff67 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -1498,7 +1498,6 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name,
 	pcm->poll_fd = fd;
 	pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
 	pcm->tstamp_type = tstamp_type;
-	pcm->monotonic = tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
 
 	ret = snd_pcm_hw_mmap_status(pcm);
 	if (ret < 0) {
diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c
index 0c61fc1..38c4ce7 100644
--- a/src/pcm/pcm_iec958.c
+++ b/src/pcm/pcm_iec958.c
@@ -534,7 +534,7 @@ int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
 	pcm->private_data = iec;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &iec->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &iec->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c
index c1c3a98..85a8891 100644
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -448,7 +448,7 @@ static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
 	if (err < 0)
 		return err;
 
-	gettimestamp(&io->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
 	io->data->state = SND_PCM_STATE_RUNNING;
 
 	return 0;
@@ -463,7 +463,7 @@ static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
 
 	io->data->callback->stop(io->data);
 
-	gettimestamp(&io->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
 	io->data->state = SND_PCM_STATE_SETUP;
 
 	return 0;
@@ -1069,7 +1069,10 @@ int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
 {
 	ioplug->pcm->poll_fd = ioplug->poll_fd;
 	ioplug->pcm->poll_events = ioplug->poll_events;
-	ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0;
+	if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
+		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
+	else
+		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
 	ioplug->pcm->mmap_rw = ioplug->mmap_rw;
 	return 0;
 }
diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c
index 7d1e3df..631ee0f 100644
--- a/src/pcm/pcm_ladspa.c
+++ b/src/pcm/pcm_ladspa.c
@@ -1641,7 +1641,7 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
 	pcm->private_data = ladspa;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c
index bbf72c2..324282f 100644
--- a/src/pcm/pcm_lfloat.c
+++ b/src/pcm/pcm_lfloat.c
@@ -412,7 +412,7 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
 	pcm->private_data = lfloat;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
index 7aa8941..3d5bbb8 100644
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -484,7 +484,7 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
 	pcm->private_data = linear;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 3ed7e1a..2206afe 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -191,7 +191,6 @@ struct _snd_pcm {
 	int poll_fd;
 	unsigned short poll_events;
 	int setup: 1,
-	    monotonic: 1,
 	    compat: 1;
 	snd_pcm_access_t access;	/* access mode */
 	snd_pcm_format_t format;	/* SND_PCM_FORMAT_* */
@@ -960,26 +959,40 @@ typedef union snd_tmp_double {
 } snd_tmp_double_t;
 
 /* get the current timestamp */
-static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic)
+#ifdef HAVE_CLOCK_GETTIME
+static inline void gettimestamp(snd_htimestamp_t *tstamp,
+				snd_pcm_tstamp_type_t tstamp_type)
 {
-#if defined(HAVE_CLOCK_GETTIME)
-#if defined(CLOCK_MONOTONIC)
-	if (monotonic) {
-		clock_gettime(CLOCK_MONOTONIC, tstamp);
-	} else {
-#endif
-		clock_gettime(CLOCK_REALTIME, tstamp);
-#else
-		struct timeval tv;
+	clockid_t id;
 
-		gettimeofday(&tv, 0);
-		tstamp->tv_sec = tv.tv_sec;
-		tstamp->tv_nsec = tv.tv_usec * 1000L;
+	switch (tstamp_type) {
+#ifdef CLOCK_MONOTONIC_RAW
+	case SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
+		id = CLOCK_MONOTONIC_RAW;
+		break;
 #endif
-#if defined(HAVE_CLOCK_GETTIME)
-	}
+#ifdef CLOCK_MONOTONIC
+	case SND_PCM_TSTAMP_TYPE_MONOTONIC:
+		id = CLOCK_MONOTONIC;
+		break;
 #endif
+	default:
+		id = CLOCK_REALTIME;
+		break;
+	}
+	clock_gettime(id, tstamp);
+}
+#else /* HAVE_CLOCK_GETTIME */
+static inline void gettimestamp(snd_htimestamp_t *tstamp,
+				snd_pcm_tstamp_type_t tstamp_type)
+{
+	struct timeval tv;
+
+	gettimeofday(&tv, 0);
+	tstamp->tv_sec = tv.tv_sec;
+	tstamp->tv_nsec = tv.tv_usec * 1000L;
 }
+#endif /* HAVE_CLOCK_GETTIME */
 
 snd_pcm_chmap_query_t **
 _snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src);
diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c
index 676fbef..034f582 100644
--- a/src/pcm/pcm_meter.c
+++ b/src/pcm/pcm_meter.c
@@ -591,7 +591,7 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc
 	pcm->private_data = meter;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c
index 63789bc..b2b15ef 100644
--- a/src/pcm/pcm_mmap_emul.c
+++ b/src/pcm/pcm_mmap_emul.c
@@ -428,7 +428,7 @@ int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name,
 	pcm->private_data = map;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c
index 7adce38..011b2a5 100644
--- a/src/pcm/pcm_mulaw.c
+++ b/src/pcm/pcm_mulaw.c
@@ -467,7 +467,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
 	pcm->private_data = mulaw;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
index a84e0ce..4b8299e 100644
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -1077,7 +1077,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
 	pcm->private_data = multi;
 	pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
 	pcm->poll_events = multi->slaves[master_slave].pcm->poll_events;
-	pcm->monotonic = multi->slaves[master_slave].pcm->monotonic;
+	pcm->tstamp_type = multi->slaves[master_slave].pcm->tstamp_type;
 	snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm);
 	snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c
index 655261f..f11a102 100644
--- a/src/pcm/pcm_null.c
+++ b/src/pcm/pcm_null.c
@@ -100,7 +100,7 @@ static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 	memset(status, 0, sizeof(*status));
 	status->state = null->state;
 	status->trigger_tstamp = null->trigger_tstamp;
-	gettimestamp(&status->tstamp, pcm->monotonic);
+	gettimestamp(&status->tstamp, pcm->tstamp_type);
 	status->avail = snd_pcm_null_avail_update(pcm);
 	status->avail_max = pcm->buffer_size;
 	return 0;
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index 7a6c2b9..5639b9e 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -1127,7 +1127,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
 	pcm->mmap_shadow = 1;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_link_hw_ptr(pcm, slave);
 	snd_pcm_link_appl_ptr(pcm, slave);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 2563d82..5e811bb 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -1069,7 +1069,7 @@ static int snd_pcm_rate_start(snd_pcm_t *pcm)
 	if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED)
 		return -EBADFD;
 
-	gettimestamp(&rate->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type);
 
 	avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave);
 	if (avail == 0) {
@@ -1372,7 +1372,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
 	pcm->mmap_rw = 1;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0);
 	*pcmp = pcm;
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 751e36f..2f0be38 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -1122,7 +1122,7 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
 	pcm->private_data = route;
 	pcm->poll_fd = slave->poll_fd;
 	pcm->poll_events = slave->poll_events;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0);
 	err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index 118ab26..9770544 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -971,7 +971,7 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
 	}
 	slave->running_count++;
 	_snd_pcm_share_update(pcm);
-	gettimestamp(&share->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
  _end:
 	Pthread_mutex_unlock(&slave->mutex);
 	return err;
@@ -1126,7 +1126,7 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state)
 		return;
 	}
 #endif
-	gettimestamp(&share->trigger_tstamp, pcm->monotonic);
+	gettimestamp(&share->trigger_tstamp, pcm->tstamp_type);
 	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 		snd_pcm_areas_copy(pcm->stopped_areas, 0,
 				   pcm->running_areas, 0,
@@ -1526,7 +1526,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
 	pcm->private_data = share;
 	pcm->poll_fd = share->client_socket;
 	pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
-	pcm->monotonic = slave->pcm->monotonic;
+	pcm->tstamp_type = slave->pcm->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
 
diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c
index 5da9204..c6cfd88 100644
--- a/src/pcm/pcm_softvol.c
+++ b/src/pcm/pcm_softvol.c
@@ -903,7 +903,7 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
 	 * an extra buffer.
 	 */
 	pcm->mmap_shadow = 1;
-	pcm->monotonic = slave->monotonic;
+	pcm->tstamp_type = slave->tstamp_type;
 	snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0);
 	snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0);
 	*pcmp = pcm;
-- 
1.9.3


From 52444bd43afbadb8637f5fac3fe5fd90575ee216 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 14 Jul 2014 18:12:49 +0200
Subject: [PATCH 10/35] test/audio_time: Set timestamp type explicitly

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 test/audio_time.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/test/audio_time.c b/test/audio_time.c
index 03817c7..7435db6 100644
--- a/test/audio_time.c
+++ b/test/audio_time.c
@@ -57,6 +57,7 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
 #define TRACK_PLAYBACK  /* dump playback timing info */
 #define TRACK_SAMPLE_COUNTS /* show difference between sample counters and audiotimestamps returned by driver */
 #define PLAYBACK_BUFFERS 4
+#define TSTAMP_TYPE	SND_PCM_TSTAMP_TYPE_MONOTONIC
 
 
 int main(void)
@@ -128,6 +129,12 @@ int main(void)
 		goto _exit;
 	}
 
+	err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
+	if (err < 0) {
+		printf("Unable to set tstamp type : %s\n", snd_strerror(err));
+		goto _exit;
+	}
+
 	/* write the sw parameters */
 	err = snd_pcm_sw_params(handle_p, swparams_p);
 	if (err < 0) {
@@ -177,6 +184,12 @@ int main(void)
 		goto _exit;
 	}
 
+	err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
+	if (err < 0) {
+		printf("Unable to set tstamp type : %s\n", snd_strerror(err));
+		goto _exit;
+	}
+
 	/* write the sw parameters */
 	err = snd_pcm_sw_params(handle_c, swparams_c);
 	if (err < 0) {
-- 
1.9.3


From de63b942acf520a25ff469cf338a99eb3da65570 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 21 Jul 2014 16:30:54 +0200
Subject: [PATCH 11/35] pcm: route: Use get/put labels for all 3 byte formats

So far, use_getput flag is set only when the src or dest format is
24bit physical width.  But, also 18 and 20 bit physical width formats
should set the flag, too.  This patch makes the check broader to cover
all 3 bytes formats.

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

diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 2f0be38..72c198c 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -644,8 +644,10 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 	}
 	if (err < 0)
 		return err;
-	route->params.use_getput = snd_pcm_format_physical_width(src_format) == 24 ||
-		snd_pcm_format_physical_width(dst_format) == 24;
+	/* 3 bytes formats? */
+	route->params.use_getput =
+		(snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 ||
+		(snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3;
 	route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16);
 	route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
 	route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
-- 
1.9.3


From 55c53625212702debf55c719ec62f6c81c780927 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 16 Jul 2014 17:48:34 +0200
Subject: [PATCH 12/35] pcm: Fill sw_params proto field

Fill the new proto field introduced to sw_params with the current PCM
protocol version.  This makes tstamp_type evaluated properly in the
kernel.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asound.h | 4 ++--
 src/pcm/pcm.c          | 1 +
 src/pcm/pcm_params.c   | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 552f41b..c819df4 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -386,8 +386,8 @@ struct snd_pcm_sw_params {
 	snd_pcm_uframes_t silence_threshold;	/* min distance from noise for silence filling */
 	snd_pcm_uframes_t silence_size;		/* silence block size */
 	snd_pcm_uframes_t boundary;		/* pointers wrap point */
-	unsigned int tstamp_type;		/* timestamp type */
-	int pads;				/* alignment, reserved */
+	unsigned int proto;			/* protocol version */
+	unsigned int tstamp_type;		/* timestamp type (req. proto >= 2.0.12) */
 	unsigned char reserved[56];		/* reserved for future */
 };
 
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 8984443..1399a5b 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -5610,6 +5610,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 		SNDMSG("PCM not set up");
 		return -EIO;
 	}
+	params->proto = SNDRV_PCM_VERSION;
 	params->tstamp_mode = pcm->tstamp_mode;
 	params->tstamp_type = pcm->tstamp_type;
 	params->period_step = pcm->period_step;
diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c
index 4adbefa..6e57904 100644
--- a/src/pcm/pcm_params.c
+++ b/src/pcm/pcm_params.c
@@ -2257,6 +2257,7 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params
 {
 	assert(pcm && params);
 	assert(pcm->setup);
+	params->proto = SNDRV_PCM_VERSION;
 	params->tstamp_mode = SND_PCM_TSTAMP_NONE;
 	params->tstamp_type = pcm->tstamp_type;
 	params->period_step = 1;
-- 
1.9.3


From fd84adc63e307572d05274be44c782a787087cda Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 22 Jul 2014 11:55:40 +0200
Subject: [PATCH 13/35] pcm: route: Use get32 for multi-source route
 calculation

The PCM route plugin can assign the destination value from average of
multiple sources with attenuation.  This requires the read of each
channel value, sums and writes the resultant value in the requested
format.

Currently, get_labels is used for reading source values while
put32_labels is used for writing the dest value.  This is, however,
a buggy implementation; get_labels gives the value as is only with
endianness and signedness conversions, but put32_labels assumes that
the value is normalized to 32bit int and it shifts down to the dest
format.  In addition, the current code lacks get_labels entries for
the 24bit formats, as Shengjiu Wang spotted out.

For fixing these bugs, this patch replaces the read with
get32_labels and use always 64bit int for sum.  This simplifies the
code a lot and drops many lines.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_route.c  | 128 +++++++++------------------------------------------
 src/pcm/plugin_ops.h |  81 --------------------------------
 2 files changed, 23 insertions(+), 186 deletions(-)

diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 72c198c..5dac7eb 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -60,7 +60,7 @@ typedef struct {
 typedef struct snd_pcm_route_ttable_dst snd_pcm_route_ttable_dst_t;
 
 typedef struct {
-	enum {UINT32=0, UINT64=1, FLOAT=2} sum_idx;
+	enum {UINT64, FLOAT} sum_idx;
 	unsigned int get_idx;
 	unsigned int put_idx;
 	unsigned int conv_idx;
@@ -233,55 +233,34 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 					const snd_pcm_route_ttable_dst_t* ttable,
 					const snd_pcm_route_params_t *params)
 {
-#define GETS_LABELS
+#define GET32_LABELS
 #define PUT32_LABELS
 #include "plugin_ops.h"
-#undef GETS_LABELS
+#undef GET32_LABELS
 #undef PUT32_LABELS
-	static void *const zero_labels[3] = {
-		&&zero_int32, &&zero_int64,
+	static void *const zero_labels[2] = {
+		&&zero_int64,
 #if SND_PCM_PLUGIN_ROUTE_FLOAT
 		&&zero_float
 #endif
 	};
 	/* sum_type att */
-	static void *const add_labels[3 * 2] = {
-		&&add_int32_noatt, &&add_int32_att,
+	static void *const add_labels[2 * 2] = {
 		&&add_int64_noatt, &&add_int64_att,
 #if SND_PCM_PLUGIN_ROUTE_FLOAT
 		&&add_float_noatt, &&add_float_att
 #endif
 	};
-	/* sum_type att shift */
-	static void *const norm_labels[3 * 2 * 4] = {
-		0,
-		&&norm_int32_8_noatt,
-		&&norm_int32_16_noatt,
-		&&norm_int32_24_noatt,
-		0,
-		&&norm_int32_8_att,
-		&&norm_int32_16_att,
-		&&norm_int32_24_att,
-		&&norm_int64_0_noatt,
-		&&norm_int64_8_noatt,
-		&&norm_int64_16_noatt,
-		&&norm_int64_24_noatt,
-		&&norm_int64_0_att,
-		&&norm_int64_8_att,
-		&&norm_int64_16_att,
-		&&norm_int64_24_att,
+	/* sum_type att */
+	static void *const norm_labels[2 * 2] = {
+		&&norm_int64_noatt,
+		&&norm_int64_att,
 #if SND_PCM_PLUGIN_ROUTE_FLOAT
-		&&norm_float_0,
-		&&norm_float_8,
-		&&norm_float_16,
-		&&norm_float_24,
-		&&norm_float_0,
-		&&norm_float_8,
-		&&norm_float_16,
-		&&norm_float_24,
+		&&norm_float,
+		&&norm_float,
 #endif
 	};
-	void *zero, *get, *add, *norm, *put32;
+	void *zero, *get32, *add, *norm, *put32;
 	int nsrcs = ttable->nsrcs;
 	char *dst;
 	int dst_step;
@@ -323,9 +302,9 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 	}
 
 	zero = zero_labels[params->sum_idx];
-	get = gets_labels[params->get_idx];
+	get32 = get32_labels[params->get_idx];
 	add = add_labels[params->sum_idx * 2 + ttable->att];
-	norm = norm_labels[params->sum_idx * 8 + ttable->att * 4 + 4 - params->src_size];
+	norm = norm_labels[params->sum_idx * 2 + ttable->att];
 	put32 = put32_labels[params->put_idx];
 	dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
 	dst_step = snd_pcm_channel_area_step(dst_area);
@@ -336,9 +315,6 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 
 		/* Zero sum */
 		goto *zero;
-	zero_int32:
-		sum.as_sint32 = 0;
-		goto zero_end;
 	zero_int64: 
 		sum.as_sint64 = 0;
 		goto zero_end;
@@ -352,21 +328,14 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 			const char *src = srcs[srcidx];
 			
 			/* Get sample */
-			goto *get;
-#define GETS_END after_get
+			goto *get32;
+#define GET32_END after_get
 #include "plugin_ops.h"
-#undef GETS_END
+#undef GET32_END
 		after_get:
 
 			/* Sum */
 			goto *add;
-		add_int32_att:
-			sum.as_sint32 += sample * ttp->as_int;
-			goto after_sum;
-		add_int32_noatt:
-			if (ttp->as_int)
-				sum.as_sint32 += sample;
-			goto after_sum;
 		add_int64_att:
 			sum.as_sint64 += (int64_t) sample * ttp->as_int;
 			goto after_sum;
@@ -390,48 +359,10 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 		
 		/* Normalization */
 		goto *norm;
-	norm_int32_8_att:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_8_att:
-		sum.as_sint64 <<= 8;
-	norm_int64_0_att:
+	norm_int64_att:
 		div(sum.as_sint64);
-		goto norm_int;
-
-	norm_int32_16_att:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_16_att:
-		sum.as_sint64 <<= 16;
-		div(sum.as_sint64);
-		goto norm_int;
-
-	norm_int32_24_att:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_24_att:
-		sum.as_sint64 <<= 24;
-		div(sum.as_sint64);
-		goto norm_int;
-
-	norm_int32_8_noatt:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_8_noatt:
-		sum.as_sint64 <<= 8;
-		goto norm_int;
-
-	norm_int32_16_noatt:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_16_noatt:
-		sum.as_sint64 <<= 16;
-		goto norm_int;
-
-	norm_int32_24_noatt:
-		sum.as_sint64 = sum.as_sint32;
-	norm_int64_24_noatt:
-		sum.as_sint64 <<= 24;
-		goto norm_int;
-
-	norm_int64_0_noatt:
-	norm_int:
+		/* fallthru */
+	norm_int64_noatt:
 		if (sum.as_sint64 > (int64_t)0x7fffffff)
 			sample = 0x7fffffff;	/* maximum positive value */
 		else if (sum.as_sint64 < -(int64_t)0x80000000)
@@ -441,16 +372,6 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
 		goto after_norm;
 
 #if SND_PCM_PLUGIN_ROUTE_FLOAT
-	norm_float_8:
-		sum.as_float *= 1 << 8;
-		goto norm_float;
-	norm_float_16:
-		sum.as_float *= 1 << 16;
-		goto norm_float;
-	norm_float_24:
-		sum.as_float *= 1 << 24;
-		goto norm_float;
-	norm_float_0:
 	norm_float:
 		sum.as_float = rint(sum.as_float);
 		if (sum.as_float > (int64_t)0x7fffffff)
@@ -648,7 +569,7 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 	route->params.use_getput =
 		(snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 ||
 		(snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3;
-	route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16);
+	route->params.get_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
 	route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
 	route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
 	route->params.src_size = snd_pcm_format_width(src_format) / 8;
@@ -656,10 +577,7 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 #if SND_PCM_PLUGIN_ROUTE_FLOAT
 	route->params.sum_idx = FLOAT;
 #else
-	if (snd_pcm_format_width(src_format) == 32)
-		route->params.sum_idx = UINT64;
-	else
-		route->params.sum_idx = UINT32;
+	route->params.sum_idx = UINT64;
 #endif
 	return 0;
 }
diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h
index 21535c9..eb8c2c4 100644
--- a/src/pcm/plugin_ops.h
+++ b/src/pcm/plugin_ops.h
@@ -668,87 +668,6 @@ getu_1234_C321: sample = bswap_32(as_u32c(src) ^ 0x80); goto GETU_END;
 }
 #endif
 
-#ifdef GETS_LABELS
-/* width endswap sign_toggle */
-static void *const gets_labels[4 * 2 * 2] = {
-	&&gets_1_1,		/*  8h ->  8h */
-	&&gets_1_9,		/*  8h ^>  8h */
-	&&gets_1_1,		/*  8s ->  8h */
-	&&gets_1_9,		/*  8s ^>  8h */
-	&&gets_12_12,		/* 16h -> 16h */
-	&&gets_12_92,		/* 16h ^> 16h */
-	&&gets_12_21,		/* 16s -> 16h */
-	&&gets_12_A1,		/* 16s ^> 16h */
-	&&gets_0123_0123,	/* 24h -> 24h */
-	&&gets_0123_0923,	/* 24h ^> 24h */
-	&&gets_1230_0321,	/* 24s -> 24h */
-	&&gets_1230_0B21,	/* 24s ^> 24h */
-	&&gets_1234_1234,	/* 32h -> 32h */
-	&&gets_1234_9234,	/* 32h ^> 32h */
-	&&gets_1234_4321,	/* 32s -> 32h */
-	&&gets_1234_C321,	/* 32s ^> 32h */
-};
-#endif
-
-#ifdef GETS_END
-while (0) {
-gets_1_1: sample = as_s8c(src); goto GETS_END;
-gets_1_9: sample = (int8_t)(as_s8c(src) ^ 0x80); goto GETS_END;
-gets_12_12: sample = as_s16c(src); goto GETS_END;
-gets_12_92: sample = (int16_t)(as_s16c(src) ^ 0x8000); goto GETS_END;
-gets_12_21: sample = (int16_t)bswap_16(as_s16c(src)); goto GETS_END;
-gets_12_A1: sample = (int16_t)bswap_16(as_s16c(src) ^ 0x80); goto GETS_END;
-gets_0123_0123: sample = sx24((int32_t)(as_s32c(src) << 8) >> 8); goto GETS_END;
-gets_0123_0923: sample = sx24((int32_t)((as_s32c(src) ^ 0x800000) << 8) >> 8); goto GETS_END;
-gets_1230_0321: sample = sx24((int32_t)(bswap_32(as_s32c(src)) << 8) >> 8); goto GETS_END;
-gets_1230_0B21: sample = sx24((int32_t)(bswap_32(as_s32c(src) ^ 0x8000) << 8) >> 8); goto GETS_END;
-gets_1234_1234: sample = as_s32c(src); goto GETS_END;
-gets_1234_9234: sample = (int32_t)(as_s32c(src) ^ 0x80000000); goto GETS_END;
-gets_1234_4321: sample = (int32_t)bswap_32(as_s32c(src)); goto GETS_END;
-gets_1234_C321: sample = (int32_t)bswap_32(as_s32c(src) ^ 0x80); goto GETS_END;
-}
-#endif
-
-#ifdef PUT_LABELS
-/* width endswap sign_toggle */
-static void *const put_labels[4 * 2 * 2] = {
-	&&put_1_1,		/*  8h ->  8h */
-	&&put_1_9,		/*  8h ^>  8h */
-	&&put_1_1,		/*  8h ->  8s */
-	&&put_1_9,		/*  8h ^>  8s */
-	&&put_12_12,		/* 16h -> 16h */
-	&&put_12_92,		/* 16h ^> 16h */
-	&&put_12_21,		/* 16h -> 16s */
-	&&put_12_29,		/* 16h ^> 16s */
-	&&put_0123_0123,	/* 24h -> 24h */
-	&&put_0123_0923,	/* 24h ^> 24h */
-	&&put_0123_3210,	/* 24h -> 24s */
-	&&put_0123_3290,	/* 24h ^> 24s */
-	&&put_1234_1234,	/* 32h -> 32h */
-	&&put_1234_9234,	/* 32h ^> 32h */
-	&&put_1234_4321,	/* 32h -> 32s */
-	&&put_1234_4329,	/* 32h ^> 32s */
-};
-#endif
-
-#ifdef PUT_END
-put_1_1: as_s8(dst) = sample; goto PUT_END;
-put_1_9: as_u8(dst) = sample ^ 0x80; goto PUT_END;
-put_12_12: as_s16(dst) = sample; goto PUT_END;
-put_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT_END;
-put_12_21: as_s16(dst) = bswap_16(sample); goto PUT_END;
-put_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT_END;
-/* this always writes the unused byte in 24-bit formats as 0x00 */
-put_0123_0123: as_s32(dst) = sx24(sample & 0x00ffffff); goto PUT_END;
-put_0123_0923: as_u32(dst) = sx24((sample & 0x00ffffff) ^ 0x800000); goto PUT_END;
-put_0123_3210: as_s32(dst) = sx24s(bswap_32(sample) & 0xffffff00); goto PUT_END;
-put_0123_3290: as_u32(dst) = sx24s((bswap_32(sample) & 0xffffff00) ^ 0x8000); goto PUT_END;
-put_1234_1234: as_s32(dst) = sample; goto PUT_END;
-put_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_END;
-put_1234_4321: as_s32(dst) = bswap_32(sample); goto PUT_END;
-put_1234_4329: as_u32(dst) = bswap_32(sample) ^ 0x80; goto PUT_END;
-#endif
-
 #ifdef PUT32F_LABELS
 /* type (0 = float, 1 = float64), endswap */
 static void *const put32float_labels[2 * 2] = {
-- 
1.9.3


From 7a5646f58ba2e8154a274a5ae0f8ec963f331f97 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 22 Jul 2014 12:20:50 +0200
Subject: [PATCH 14/35] pcm: Drop snd_pcm_linear_{get|put}32_index()

These are identical with snd_pcm_linear_{get|put}_index().

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_lfloat.c |  4 ++--
 src/pcm/pcm_linear.c | 44 ++++----------------------------------------
 src/pcm/pcm_plugin.h |  4 ----
 src/pcm/pcm_route.c  |  4 ++--
 4 files changed, 8 insertions(+), 48 deletions(-)

diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c
index 324282f..2f3e578 100644
--- a/src/pcm/pcm_lfloat.c
+++ b/src/pcm/pcm_lfloat.c
@@ -286,11 +286,11 @@ static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 		err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format);
 	}
 	if (snd_pcm_format_linear(src_format)) {
-		lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
+		lfloat->int32_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32);
 		lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format);
 		lfloat->func = snd_pcm_lfloat_convert_integer_float;
 	} else {
-		lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
+		lfloat->int32_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
 		lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format);
 		lfloat->func = snd_pcm_lfloat_convert_float_integer;
 	}
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
index 3d5bbb8..9a92abd 100644
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -107,11 +107,6 @@ int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
 	}
 }
 
-int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
-{
-	return snd_pcm_linear_get_index(src_format, dst_format);
-}
-
 int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
 {
 	int sign, width, pwidth, endian;
@@ -143,37 +138,6 @@ int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
 	}
 }
 
-int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
-{
-	int sign, width, pwidth, endian;
-	sign = (snd_pcm_format_signed(src_format) != 
-		snd_pcm_format_signed(dst_format));
-#ifdef SND_LITTLE_ENDIAN
-	endian = snd_pcm_format_big_endian(dst_format);
-#else
-	endian = snd_pcm_format_little_endian(dst_format);
-#endif
-	if (endian < 0)
-		endian = 0;
-	pwidth = snd_pcm_format_physical_width(dst_format);
-	width = snd_pcm_format_width(dst_format);
-	if (pwidth == 24) {
-		switch (width) {
-		case 24:
-			width = 0; break;
-		case 20:
-			width = 1; break;
-		case 18:
-		default:
-			width = 2; break;
-		}
-		return width * 4 + endian * 2 + sign + 16;
-	} else {
-		width = width / 8 - 1;
-		return width * 4 + endian * 2 + sign;
-	}
-}
-
 void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
 			    const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
 			    unsigned int channels, snd_pcm_uframes_t frames,
@@ -342,11 +306,11 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 			      snd_pcm_format_physical_width(linear->sformat) == 24);
 	if (linear->use_getput) {
 		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-			linear->get_idx = snd_pcm_linear_get32_index(format, SND_PCM_FORMAT_S32);
-			linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, linear->sformat);
+			linear->get_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32);
+			linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, linear->sformat);
 		} else {
-			linear->get_idx = snd_pcm_linear_get32_index(linear->sformat, SND_PCM_FORMAT_S32);
-			linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, format);
+			linear->get_idx = snd_pcm_linear_get_index(linear->sformat, SND_PCM_FORMAT_S32);
+			linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, format);
 		}
 	} else {
 		if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h
index 19e82c3..b0a3e18 100644
--- a/src/pcm/pcm_plugin.h
+++ b/src/pcm/pcm_plugin.h
@@ -86,8 +86,6 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic
 /* make local functions really local */
 #define snd_pcm_linear_get_index	snd1_pcm_linear_get_index
 #define snd_pcm_linear_put_index	snd1_pcm_linear_put_index
-#define snd_pcm_linear_get32_index	snd1_pcm_linear_get32_index
-#define snd_pcm_linear_put32_index	snd1_pcm_linear_put32_index
 #define snd_pcm_linear_convert_index	snd1_pcm_linear_convert_index
 #define snd_pcm_linear_convert	snd1_pcm_linear_convert
 #define snd_pcm_linear_getput	snd1_pcm_linear_getput
@@ -100,8 +98,6 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic
 
 int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
-int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
-int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 
 void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 5dac7eb..e7de9b5 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -569,8 +569,8 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 	route->params.use_getput =
 		(snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 ||
 		(snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3;
-	route->params.get_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
-	route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
+	route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32);
+	route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
 	route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
 	route->params.src_size = snd_pcm_format_width(src_format) / 8;
 	route->params.dst_sfmt = dst_format;
-- 
1.9.3


From f6b879e7cc87d83343f5004369146881d1d1e335 Mon Sep 17 00:00:00 2001
From: Shengjiu Wang <shengjiu.wang@freescale.com>
Date: Wed, 23 Jul 2014 15:09:58 +0800
Subject: [PATCH 15/35] pcm: pcm_local.h: include <time.h> to enable
 CLOCK_MONOTONIC

CLOCK_MONITONIC is defined in <bits/time.h>, add <time.h> before
<sys/time.h>.

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

diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 2206afe..80bbe59 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <sys/uio.h>
+#include <time.h>
 #include <sys/time.h>
 
 #define _snd_mask sndrv_mask
-- 
1.9.3


From 87df9f3b7a650418b9aef943ac246549c132672a Mon Sep 17 00:00:00 2001
From: Jurgen Kramer <gtmkramer@xs4all.nl>
Date: Sat, 9 Aug 2014 12:09:21 +0200
Subject: [PATCH 16/35] pcm: Fix DSD formats userland usability

Support for DSD sample formats has been added a while ago. This patch makes
those sample formats beter usable from userland (e.g. aplay).

[These implementation details have been forgotten in the previous DSD
 support patch -- tiwai]

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asound.h | 4 +++-
 src/pcm/pcm_misc.c     | 4 ++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index c819df4..5194524 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t;
 #define	SNDRV_PCM_FORMAT_G723_24_1B	((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
 #define	SNDRV_PCM_FORMAT_G723_40	((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
 #define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_G723_40_1B
+#define SNDRV_PCM_FORMAT_DSD_U8		((__force snd_pcm_format_t) 48) /* 8 1-bit samples in 1 byte */
+#define SNDRV_PCM_FORMAT_DSD_U16_LE	((__force snd_pcm_format_t) 49) /* 16 1-bit samples in 2 bytes */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U16_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index d52160c..44bb89c 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -195,11 +195,13 @@ int snd_pcm_format_width(snd_pcm_format_t format)
 	switch (format) {
 	case SNDRV_PCM_FORMAT_S8:
 	case SNDRV_PCM_FORMAT_U8:
+	case SNDRV_PCM_FORMAT_DSD_U8:
 		return 8;
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_BE:
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
 		return 16;
 	case SNDRV_PCM_FORMAT_S18_3LE:
 	case SNDRV_PCM_FORMAT_S18_3BE:
@@ -253,11 +255,13 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
 	switch (format) {
 	case SNDRV_PCM_FORMAT_S8:
 	case SNDRV_PCM_FORMAT_U8:
+	case SNDRV_PCM_FORMAT_DSD_U8:
 		return 8;
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_BE:
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
 		return 16;
 	case SNDRV_PCM_FORMAT_S18_3LE:
 	case SNDRV_PCM_FORMAT_S18_3BE:
-- 
1.9.3


From 717ae3dd90c37f3a5ea9809370bdf56e2590a1c4 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 11 Aug 2014 11:51:29 +0200
Subject: [PATCH 17/35] Sync include/sound/asound.h with 3.17-rc1 kernel

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/sound/asound.h | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 5194524..32168f7 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -93,9 +93,12 @@ enum {
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
 	SNDRV_HWDEP_IFACE_HDA,		/* HD-audio */
 	SNDRV_HWDEP_IFACE_USB_STREAM,	/* direct access to usb stream */
+	SNDRV_HWDEP_IFACE_FW_DICE,	/* TC DICE FireWire device */
+	SNDRV_HWDEP_IFACE_FW_FIREWORKS,	/* Echo Audio Fireworks based device */
+	SNDRV_HWDEP_IFACE_FW_BEBOB,	/* BridgeCo BeBoB based device */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_BEBOB
 };
 
 struct snd_hwdep_info {
@@ -214,8 +217,8 @@ typedef int __bitwise snd_pcm_format_t;
 #define	SNDRV_PCM_FORMAT_G723_24_1B	((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
 #define	SNDRV_PCM_FORMAT_G723_40	((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
 #define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define SNDRV_PCM_FORMAT_DSD_U8		((__force snd_pcm_format_t) 48) /* 8 1-bit samples in 1 byte */
-#define SNDRV_PCM_FORMAT_DSD_U16_LE	((__force snd_pcm_format_t) 49) /* 16 1-bit samples in 2 bytes */
+#define	SNDRV_PCM_FORMAT_DSD_U8		((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
+#define	SNDRV_PCM_FORMAT_DSD_U16_LE	((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
 #define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U16_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
@@ -461,7 +464,7 @@ struct snd_xfern {
 enum {
 	SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,	/* gettimeofday equivalent */
 	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,	/* posix_clock_monotonic equivalent */
-	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW,	/* monotonic_raw (no NTP) */
+	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW,    /* monotonic_raw (no NTP) */
 	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
 };
 
@@ -820,6 +823,8 @@ typedef int __bitwise snd_ctl_elem_iface_t;
 #define SNDRV_CTL_POWER_D3hot		(SNDRV_CTL_POWER_D3|0x0000)	/* Off, with power */
 #define SNDRV_CTL_POWER_D3cold		(SNDRV_CTL_POWER_D3|0x0001)	/* Off, without power */
 
+#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN	44
+
 struct snd_ctl_elem_id {
 	unsigned int numid;		/* numeric identifier, zero = invalid */
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
-- 
1.9.3


From e8e54811339b13d6df648bb48b35157d9fba352c Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 11 Aug 2014 11:55:03 +0200
Subject: [PATCH 18/35] pcm: Add missing signed and endianess definitions for
 DSD formats

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

diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index 44bb89c..24d52f9 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -62,6 +62,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_U20_3BE:
 	case SNDRV_PCM_FORMAT_U18_3LE:
 	case SNDRV_PCM_FORMAT_U18_3BE:
+	case SNDRV_PCM_FORMAT_DSD_U8:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
 		return 0;
 	default:
 		return -EINVAL;
@@ -150,6 +152,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_U24_3BE:
 	case SNDRV_PCM_FORMAT_U20_3BE:
 	case SNDRV_PCM_FORMAT_U18_3BE:
+	case SNDRV_PCM_FORMAT_DSD_U8:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
 		return 0;
 	default:
 		return -EINVAL;
-- 
1.9.3


From dfc3bf97bf45bd78d498d20fcf930541350f836d Mon Sep 17 00:00:00 2001
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Date: Mon, 18 Aug 2014 18:45:17 +0900
Subject: [PATCH 19/35] Sync enum snd_hwdep_iface_t with
 include/asound/asound.h

Some members in this enumerated type has not updated for 9 years, although
kernel-drivers added them during this period. This commit adds them following
to a commit 87df9f3 'sync include/asound/asound.h with 3.17-rc1 kernel'.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/hwdep.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/hwdep.h b/include/hwdep.h
index ab12822..6496fa2 100644
--- a/include/hwdep.h
+++ b/include/hwdep.h
@@ -68,8 +68,13 @@ typedef enum _snd_hwdep_iface {
 	SND_HWDEP_IFACE_USX2Y_PCM,	/**< Tascam US122, US224 & US428 raw USB PCM */
 	SND_HWDEP_IFACE_PCXHR,		/**< Digigram PCXHR */
 	SND_HWDEP_IFACE_SB_RC,		/**< SB Extigy/Audigy2NX remote control */
-                
-	SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_SB_RC  /**< last known hwdep interface */
+	SND_HWDEP_IFACE_HDA,		/**< HD-audio */
+	SND_HWDEP_IFACE_USB_STREAM,	/**< direct access to usb stream */
+	SND_HWDEP_IFACE_FW_DICE,	/**< TC DICE FireWire device */
+	SND_HWDEP_IFACE_FW_FIREWORKS,	/**< Echo Audio Fireworks based device */
+	SND_HWDEP_IFACE_FW_BEBOB,	/**< BridgeCo BeBoB based device */
+
+	SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_FW_BEBOB  /**< last known hwdep interface */
 } snd_hwdep_iface_t;
 
 /** open for reading */
-- 
1.9.3


From b9f58dcc6f91fde42e6dd2bb831d6063855512a7 Mon Sep 17 00:00:00 2001
From: Jurgen Kramer <gtmkramer@xs4all.nl>
Date: Fri, 22 Aug 2014 10:15:10 +0200
Subject: [PATCH 20/35] pcm: 2nd round of pcm_misc DSD fixes

Functions 'snd_pcm_format_silence_64' and 'snd_pcm_format_size' also need to be
able to handle the DSD smaple format.

Changes from v1:
- Correct silence pattern for DSD

Signed-off-by: Jurgen Kramer <gtmkramer@xs4all.nl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_misc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index 24d52f9..46fc771 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -317,11 +317,13 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
 	switch (format) {
 	case SNDRV_PCM_FORMAT_S8:
 	case SNDRV_PCM_FORMAT_U8:
+	case SNDRV_PCM_FORMAT_DSD_U8:
 		return samples;
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_BE:
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
 		return samples * 2;
 	case SNDRV_PCM_FORMAT_S18_3LE:
 	case SNDRV_PCM_FORMAT_S18_3BE:
@@ -390,6 +392,9 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
 		return 0;
 	case SNDRV_PCM_FORMAT_U8:
 		return 0x8080808080808080ULL;
+	case SNDRV_PCM_FORMAT_DSD_U8:
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
+		return 0x6969696969696969ULL;
 #ifdef SNDRV_LITTLE_ENDIAN
 	case SNDRV_PCM_FORMAT_U16_LE:
 		return 0x8000800080008000ULL;
-- 
1.9.3


From 5f1960e3d8d56aa63afe2c37c6a3f4aa03571627 Mon Sep 17 00:00:00 2001
From: Dmitry Voytik <voytikd@gmail.com>
Date: Fri, 22 Aug 2014 14:17:10 +0400
Subject: [PATCH 21/35] doc: fix cross-compiling example

Simplest way to configure cross-compilation with configure
script is to pass '--host' option.
Passing just '--target' doesn't work.

Signed-off-by: Dmitry Voytik <voytikd@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 INSTALL | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/INSTALL b/INSTALL
index 91a8648..47086e3 100644
--- a/INSTALL
+++ b/INSTALL
@@ -78,16 +78,13 @@ When you would like to cross-compile ALSA library (e.g. compile on
 i686 host but for arm architecture) you will need to call ./configure
 script with additional parameters:
 
-CC=arm-linux-gcc ./configure --target=arm-linux
+CC=arm-linux-gcc ./configure --host=arm-linux
 
-In this example host where the library is build is guessed (should be
-given with --host=platform) and target for which is the library build is
-Linux on ARM architecture.  You should omit setting 'CC' variable and
-cross-compiler will be guessed too.
+You can omit setting 'CC' variable and cross-compiler will be guessed too.
 
 So simplest version would be:
 
-./configure --target=arm-linux
+./configure --host=arm-linux
 
 For platform names in the form cpu-vendor-os (or aliases for this)
 you should look in 'config.guess' script. Target and all paths
-- 
1.9.3


From 99a2254f5f2a085b81efcc80950033a2b6110ecd Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 31 Aug 2014 22:23:47 +0600
Subject: [PATCH 22/35] pcm: fix snd_pcm_mmap_hw_avail() near the boundary

This function returned incorrect results when hw.ptr was near the
boundary and hw.appl_ptr was near zero. Here "incorrect" means "greater
than the boundary".

The result was incorrect, because it was used as a return value of
various *_rewindable() functions and also as the delay for ioplug.

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_local.h | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 80bbe59..74ebd60 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -461,13 +461,7 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
 
 static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
 {
-	snd_pcm_sframes_t avail;
-	avail = *pcm->hw.ptr - *pcm->appl.ptr;
-	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-		avail += pcm->buffer_size;
-	if (avail < 0)
-		avail += pcm->boundary;
-	return pcm->buffer_size - avail;
+	return pcm->buffer_size - snd_pcm_mmap_avail(pcm);
 }
 
 static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
-- 
1.9.3


From 622b1b6bdbb34baca885b65643d4796057574eb7 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Tue, 2 Sep 2014 01:29:36 +0600
Subject: [PATCH 23/35] pcm: fix return value of snd_pcm_share_slave_avail

The return value was wrong for playback if slave->hw_ptr was near the
boundary and *pcm->appl.ptr was near zero. The wrong result was greater
than the boundary.

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 src/pcm/pcm_share.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index 9770544..c301c7a 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -128,6 +128,8 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
 		avail += pcm->buffer_size;
 	if (avail < 0)
 		avail += pcm->boundary;
+	else if ((snd_pcm_uframes_t) avail >= pcm->boundary)
+		avail -= pcm->boundary;
 	return avail;
 }
 
-- 
1.9.3


From e59ffbf30ec13f7f1615ba266ec2f3e770801d6f Mon Sep 17 00:00:00 2001
From: Jurgen Kramer <gtmkramer@xs4all.nl>
Date: Wed, 10 Sep 2014 09:00:28 +0200
Subject: [PATCH 24/35] pcm: add new 32-bit DSD sample format

Add the new DSD_U32_LE sample format to alsa-lib.

NB include/pcm.h and include/sound/asound.h are updated so a new sync with the
kernel headers is not needed

Signed-off-by: Jurgen Kramer <gtmkramer@xs4all.nl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 include/pcm.h          | 4 +++-
 include/sound/asound.h | 3 ++-
 src/pcm/pcm.c          | 2 ++
 src/pcm/pcm_misc.c     | 6 ++++++
 4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/pcm.h b/include/pcm.h
index 11e9f0d..db88ad5 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -211,7 +211,9 @@ typedef enum _snd_pcm_format {
 	SND_PCM_FORMAT_DSD_U8,
 	/* Direct Stream Digital (DSD) in 2-byte samples (x16) */
 	SND_PCM_FORMAT_DSD_U16_LE,
-	SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U16_LE,
+	/* Direct Stream Digital (DSD) in 4-byte samples (x32) */
+	SND_PCM_FORMAT_DSD_U32_LE,
+	SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U32_LE,
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	/** Signed 16 bit CPU endian */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 32168f7..6ee5867 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -219,7 +219,8 @@ typedef int __bitwise snd_pcm_format_t;
 #define	SNDRV_PCM_FORMAT_G723_40_1B	((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
 #define	SNDRV_PCM_FORMAT_DSD_U8		((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
 #define	SNDRV_PCM_FORMAT_DSD_U16_LE	((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
-#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U16_LE
+#define	SNDRV_PCM_FORMAT_DSD_U32_LE	((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_DSD_U32_LE
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 1399a5b..2e24338 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -1565,6 +1565,7 @@ static const char *const snd_pcm_format_names[] = {
 	FORMAT(G723_40_1B),
 	FORMAT(DSD_U8),
 	FORMAT(DSD_U16_LE),
+	FORMAT(DSD_U32_LE),
 };
 
 static const char *const snd_pcm_format_aliases[SND_PCM_FORMAT_LAST+1] = {
@@ -1624,6 +1625,7 @@ static const char *const snd_pcm_format_descriptions[] = {
 	FORMATD(G723_40_1B, "G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte"),
 	FORMATD(DSD_U8,  "Direct Stream Digital, 1-byte (x8), oldest bit in MSB"),
 	FORMATD(DSD_U16_LE, "Direct Stream Digital, 2-byte (x16), little endian, oldest bits in MSB"),
+	FORMATD(DSD_U32_LE, "Direct Stream Digital, 4-byte (x32), little endian, oldest bits in MSB"),
 };
 
 static const char *const snd_pcm_type_names[] = {
diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index 46fc771..9272179 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -64,6 +64,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_U18_3BE:
 	case SNDRV_PCM_FORMAT_DSD_U8:
 	case SNDRV_PCM_FORMAT_DSD_U16_LE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return 0;
 	default:
 		return -EINVAL;
@@ -154,6 +155,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_U18_3BE:
 	case SNDRV_PCM_FORMAT_DSD_U8:
 	case SNDRV_PCM_FORMAT_DSD_U16_LE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return 0;
 	default:
 		return -EINVAL;
@@ -232,6 +234,7 @@ int snd_pcm_format_width(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_U32_BE:
 	case SNDRV_PCM_FORMAT_FLOAT_LE:
 	case SNDRV_PCM_FORMAT_FLOAT_BE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return 32;
 	case SNDRV_PCM_FORMAT_FLOAT64_LE:
 	case SNDRV_PCM_FORMAT_FLOAT64_BE:
@@ -292,6 +295,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
 	case SNDRV_PCM_FORMAT_FLOAT_BE:
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return 32;
 	case SNDRV_PCM_FORMAT_FLOAT64_LE:
 	case SNDRV_PCM_FORMAT_FLOAT64_BE:
@@ -348,6 +352,7 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
 	case SNDRV_PCM_FORMAT_U32_BE:
 	case SNDRV_PCM_FORMAT_FLOAT_LE:
 	case SNDRV_PCM_FORMAT_FLOAT_BE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return samples * 4;
 	case SNDRV_PCM_FORMAT_FLOAT64_LE:
 	case SNDRV_PCM_FORMAT_FLOAT64_BE:
@@ -394,6 +399,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
 		return 0x8080808080808080ULL;
 	case SNDRV_PCM_FORMAT_DSD_U8:
 	case SNDRV_PCM_FORMAT_DSD_U16_LE:
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
 		return 0x6969696969696969ULL;
 #ifdef SNDRV_LITTLE_ENDIAN
 	case SNDRV_PCM_FORMAT_U16_LE:
-- 
1.9.3


From 9a56a673a6cd7343a9345921e2b1cbbb43fb725f Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:13 +0600
Subject: [PATCH 25/35] dmix: actually rewind when running or being drained

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_dmix.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index 7c53509..73cbe3f 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -669,11 +669,15 @@ 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;
+	int err;
 	const snd_pcm_channel_area_t *src_areas, *dst_areas;
 
 	if (dmix->state == SND_PCM_STATE_RUNNING ||
-	    dmix->state == SND_PCM_STATE_DRAINING)
-	    	return snd_pcm_dmix_hwsync(pcm);
+	    dmix->state == SND_PCM_STATE_DRAINING) {
+		err = snd_pcm_dmix_hwsync(pcm);
+		if (err < 0)
+			return err;
+	}
 
 	if (dmix->last_appl_ptr < dmix->appl_ptr)
 		size = dmix->appl_ptr - dmix->last_appl_ptr;
-- 
1.9.3


From 9a43dc15b2979ed6d8850b033b594fbef829c991 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:14 +0600
Subject: [PATCH 26/35] pcm: express the rewind size limitation logic better

There are a few places where the argument of the .rewind or .forward
callback is checked against the same value as returned by .rewindable or
.forwardable. Express this "don't rewind more than rewindable" logic
explicitly, so that the future fixes to the rewindable size can go to
one function instead of two.

While at it, take advantage of the fact that snd_pcm_mmap_avail() cannot
return negative values (except due to integer overflow, which is AFAICS
impossible given the current boundary choice).

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_dmix.c   | 4 +---
 src/pcm/pcm_dshare.c | 6 ++----
 src/pcm/pcm_dsnoop.c | 6 ++----
 src/pcm/pcm_plugin.c | 4 ++--
 4 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index 73cbe3f..ffde12a 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -751,9 +751,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
 {
 	snd_pcm_sframes_t avail;
 
-	avail = snd_pcm_mmap_playback_avail(pcm);
-	if (avail < 0)
-		return 0;
+	avail = snd_pcm_dmix_forwardable(pcm);
 	if (frames > (snd_pcm_uframes_t)avail)
 		frames = avail;
 	snd_pcm_mmap_appl_forward(pcm, frames);
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index b985172..f1a1a1d 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -419,7 +419,7 @@ static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
 {
 	snd_pcm_sframes_t avail;
 
-	avail = snd_pcm_mmap_playback_hw_avail(pcm);
+	avail = snd_pcm_dshare_rewindable(pcm);
 	if (avail < 0)
 		return 0;
 	if (frames > (snd_pcm_uframes_t)avail)
@@ -437,9 +437,7 @@ static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_
 {
 	snd_pcm_sframes_t avail;
 
-	avail = snd_pcm_mmap_playback_avail(pcm);
-	if (avail < 0)
-		return 0;
+	avail = snd_pcm_dshare_forwardable(pcm);
 	if (frames > (snd_pcm_uframes_t)avail)
 		frames = avail;
 	snd_pcm_mmap_appl_forward(pcm, frames);
diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index 0f9c9df..e56e402 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -342,9 +342,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
 {
 	snd_pcm_sframes_t avail;
 
-	avail = snd_pcm_mmap_capture_avail(pcm);
-	if (avail < 0)
-		return 0;
+	avail = snd_pcm_dsnoop_rewindable(pcm);
 	if (frames > (snd_pcm_uframes_t)avail)
 		frames = avail;
 	snd_pcm_mmap_appl_backward(pcm, frames);
@@ -360,7 +358,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_
 {
 	snd_pcm_sframes_t avail;
 
-	avail = snd_pcm_mmap_capture_hw_avail(pcm);
+	avail = snd_pcm_dsnoop_forwardable(pcm);
 	if (avail < 0)
 		return 0;
 	if (frames > (snd_pcm_uframes_t)avail)
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index 4ddf10c..a607ccf 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -204,7 +204,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm)
 snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
 {
 	snd_pcm_plugin_t *plugin = pcm->private_data;
-	snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm);
+	snd_pcm_sframes_t n = snd_pcm_plugin_rewindable(pcm);
 	snd_pcm_sframes_t sframes;
 
 	if ((snd_pcm_uframes_t)n < frames)
@@ -232,7 +232,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm)
 snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
 {
 	snd_pcm_plugin_t *plugin = pcm->private_data;
-	snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm);
+	snd_pcm_sframes_t n = snd_pcm_plugin_forwardable(pcm);
 	snd_pcm_sframes_t sframes;
 
 	if ((snd_pcm_uframes_t)n < frames)
-- 
1.9.3


From 78c804fc9348e4c29f1c77dd4b6ad586393aa628 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:15 +0600
Subject: [PATCH 27/35] pcm: handle negative values from snd_pcm_mmap_hw_avail

Such negative values can happen when an underrun happens and xrun
detection is disabled. Another situation is if the device updated the
pointer before alsa-lib has a chance to detect the xrun.

The problem is that these negative values could propagate to the
snd_pcm_rewindable return value, where it is specified that negative
returns must be interpreted as error codes and not as negative amount of
samples.

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_dmix.c   |  2 +-
 src/pcm/pcm_dshare.c |  4 +---
 src/pcm/pcm_hw.c     |  2 +-
 src/pcm/pcm_ioplug.c |  2 +-
 src/pcm/pcm_local.h  | 18 ++++++++++++++++++
 src/pcm/pcm_plugin.c |  2 +-
 6 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c
index ffde12a..babde6a 100644
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -661,7 +661,7 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIB
 
 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_hw_avail(pcm);
+	return snd_pcm_mmap_playback_hw_rewindable(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c
index f1a1a1d..020e6f7 100644
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -412,7 +412,7 @@ static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTR
 
 static snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_playback_hw_avail(pcm);
+	return snd_pcm_mmap_playback_hw_rewindable(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
@@ -420,8 +420,6 @@ static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
 	snd_pcm_sframes_t avail;
 
 	avail = snd_pcm_dshare_rewindable(pcm);
-	if (avail < 0)
-		return 0;
 	if (frames > (snd_pcm_uframes_t)avail)
 		frames = avail;
 	snd_pcm_mmap_appl_backward(pcm, frames);
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index 74cff67..c34b766 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -659,7 +659,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
 
 static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_hw_avail(pcm);
+	return snd_pcm_mmap_hw_rewindable(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c
index 85a8891..fe9347c 100644
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -503,7 +503,7 @@ static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
 
 static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_hw_avail(pcm);
+	return snd_pcm_mmap_hw_rewindable(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 74ebd60..394505f 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -464,6 +464,24 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
 	return pcm->buffer_size - snd_pcm_mmap_avail(pcm);
 }
 
+static inline snd_pcm_sframes_t snd_pcm_mmap_playback_hw_rewindable(snd_pcm_t *pcm)
+{
+	snd_pcm_sframes_t ret = snd_pcm_mmap_playback_hw_avail(pcm);
+	return (ret >= 0) ? ret : 0;
+}
+
+static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_rewindable(snd_pcm_t *pcm)
+{
+	snd_pcm_sframes_t ret = snd_pcm_mmap_capture_hw_avail(pcm);
+	return (ret >= 0) ? ret : 0;
+}
+
+static inline snd_pcm_uframes_t snd_pcm_mmap_hw_rewindable(snd_pcm_t *pcm)
+{
+	snd_pcm_sframes_t ret = snd_pcm_mmap_hw_avail(pcm);
+	return (ret >= 0) ? ret : 0;
+}
+
 static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
 {
 	if (pcm->stopped_areas &&
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index a607ccf..c19e2f1 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -198,7 +198,7 @@ static int snd_pcm_plugin_reset(snd_pcm_t *pcm)
 
 static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_hw_avail(pcm);
+	return snd_pcm_mmap_hw_rewindable(pcm);
 }
 
 snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
-- 
1.9.3


From 0889e9470667dd68d5a0ce47a10a8c6d61b7bc79 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:16 +0600
Subject: [PATCH 28/35] pcm, rate: use the snd_pcm_mmap_hw_avail function

instead of the open-coded equivalent

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_rate.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 5e811bb..b436a8e 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -593,10 +593,7 @@ static int snd_pcm_rate_hwsync(snd_pcm_t *pcm)
 static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
 {
 	snd_pcm_rate_hwsync(pcm);
-	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-		*delayp = snd_pcm_mmap_playback_hw_avail(pcm);
-	else
-		*delayp = snd_pcm_mmap_capture_hw_avail(pcm);
+	*delayp = snd_pcm_mmap_hw_avail(pcm);
 	return 0;
 }
 
-- 
1.9.3


From 4fafa468d4bb4618cfde7183f820d8fdd373dcb1 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:17 +0600
Subject: [PATCH 29/35] pcm, null: use the snd_pcm_mmap_avail function

instead of the open-coded equivalent

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_null.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c
index f11a102..0529820 100644
--- a/src/pcm/pcm_null.c
+++ b/src/pcm/pcm_null.c
@@ -86,10 +86,7 @@ static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
         if (null->state == SND_PCM_STATE_PREPARED) {
                 /* it is required to return the correct avail count for */
                 /* the prepared stream, otherwise the start is not called */
-                if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-                        return snd_pcm_mmap_playback_avail(pcm);
-                else
-                        return snd_pcm_mmap_capture_avail(pcm);
+                return snd_pcm_mmap_avail(pcm);
         }
 	return pcm->buffer_size;
 }
-- 
1.9.3


From ff9d213ff80f6fe0456565d4f524366443217174 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:18 +0600
Subject: [PATCH 30/35] rate: handle negative values from
 snd_pcm_mmap_playback_hw_avail

Such negative returns are possible during an underrun if xrun detection
is disabled.

So, don't store the result in an unsigned variable (where it will
overflow), and postpone the trigger in such case, too.

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_rate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index b436a8e..736d558 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -1058,7 +1058,7 @@ static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm)
 static int snd_pcm_rate_start(snd_pcm_t *pcm)
 {
 	snd_pcm_rate_t *rate = pcm->private_data;
-	snd_pcm_uframes_t avail;
+	snd_pcm_sframes_t avail;
 		
 	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
 		return snd_pcm_start(rate->gen.slave);
@@ -1069,7 +1069,7 @@ static int snd_pcm_rate_start(snd_pcm_t *pcm)
 	gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type);
 
 	avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave);
-	if (avail == 0) {
+	if (avail <= 0) {
 		/* postpone the trigger since we have no data committed yet */
 		rate->start_pending = 1;
 		return 0;
-- 
1.9.3


From e5e1af83881e4dbe20749a314703db7d0fd091c7 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov@gmail.com>
Date: Sun, 14 Sep 2014 00:30:19 +0600
Subject: [PATCH 31/35] dsnoop: rewindable and forwardable logic was swapped

Signed-off-by: Alexander E. Patrakov <patrakov@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 src/pcm/pcm_dsnoop.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c
index e56e402..8333eef 100644
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -335,7 +335,7 @@ static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTR
 
 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_capture_avail(pcm);
+	return snd_pcm_mmap_capture_hw_avail(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
@@ -351,7 +351,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
 
 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
 {
-	return snd_pcm_mmap_capture_hw_avail(pcm);
+	return snd_pcm_mmap_capture_avail(pcm);
 }
 
 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
@@ -359,8 +359,6 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_
 	snd_pcm_sframes_t avail;
 
 	avail = snd_pcm_dsnoop_forwardable(pcm);
-	if (avail < 0)
-		return 0;
 	if (frames > (snd_pcm_uframes_t)avail)
 		frames = avail;
 	snd_pcm_mmap_appl_forward(pcm, frames);
-- 
1.9.3


From 650b8c975cd5c3f7dca6e78e74db587b57bcdfd8 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Tue, 16 Sep 2014 09:00:39 +0200
Subject: [PATCH 35/35] pcm route: Fix the bad condition (always false)

---
 src/pcm/pcm_route.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index e7de9b5..2a437e8 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -1147,7 +1147,7 @@ static int _snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_ent
 		snd_config_iterator_t j, jnext;
 		long cchannel;
 		const char *id;
-		if (!snd_config_get_id(in, &id) < 0)
+		if (snd_config_get_id(in, &id) < 0)
 			continue;
 		err = safe_strtol(id, &cchannel);
 		if (err < 0 || 
-- 
1.9.3