From 4ff9ea5681af5730ab6236337a7920bb2837965b Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
Date: Wed, 10 Nov 2010 15:09:18 -0600
Subject: [PATCH 2/2] add API to disable period wakeups

2nd cleaned-up version of the patch posted on May 17, 2010 by
Clemens Ladisch <clemens@ladisch.de>
(No filtering in pcm_multi and pcm_direct info fields)

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
---
 include/pcm.h          |    2 +
 include/sound/asound.h |    5 +++-
 src/pcm/pcm.c          |   57 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/pcm/pcm_local.h    |    1 +
 4 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/include/pcm.h b/include/pcm.h
index f3618c3..4ecf5fa 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -626,6 +626,8 @@ int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *par
 int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
 int snd_pcm_hw_params_set_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
 int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
+int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
+int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val);
 
 int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
 int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
diff --git a/include/sound/asound.h b/include/sound/asound.h
index fa88938..a6b0fe3 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -278,6 +278,8 @@ enum sndrv_pcm_subformat {
 #define SNDRV_PCM_INFO_HALF_DUPLEX	0x00100000	/* only half duplex */
 #define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
+#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000      /* period wakeup can be disabled */
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
 enum sndrv_pcm_state {
 	SNDRV_PCM_STATE_OPEN = 0,	/* stream is open */
@@ -346,7 +348,8 @@ enum sndrv_pcm_hw_param {
 
 #define SNDRV_PCM_HW_PARAMS_NORESAMPLE	(1<<0)  /* avoid rate resampling */
 #define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER	(1<<1)  /* export buffer */
-
+#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP    (1<<2)  /* disable period
+                                                          wakeups */
 struct sndrv_interval {
 	unsigned int min, max;
 	unsigned int openmin:1,
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index a49b5b9..3dd61f6 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -726,8 +726,13 @@ int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock)
 		return err;
 	if (nonblock)
 		pcm->mode |= SND_PCM_NONBLOCK;
-	else
+	else {
+                if (pcm->hw_flags & SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP)
+                        /* can't use blocking mode if wakeup where disabled */
+                        return -EINVAL;
+                
 		pcm->mode &= ~SND_PCM_NONBLOCK;
+        }
 	return 0;
 }
 
@@ -4200,6 +4205,56 @@ int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *par
 }
 
 /**
+ * \brief Restrict a configuration space to settings without period wakeups
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val 0 = disable, 1 = enable (default) period wakeup
+ * \return Zero on success, otherwise a negative error code.
+ *
+ * This function should be called only on devices where non-blocking mode
+ * is enabled. After finalizing the hw_params, the application should verify
+ * if wakeups are indeed disabled by calling
+ * #snd_pcm_hw_params_get_period_wakeup(). If the hardware does not support
+ * this mode, standard period wakeups will be generated.
+ *
+ * Even with disabled period interrupts, the period size/time/count parameters
+ * are valid; it is suggested to use #snd_pcm_hw_params_set_period_size_last().
+ *
+ * When period wakeups are disabled, the application must not use any functions
+ * that could block on this device. The use of poll should be limited to error
+ * cases. The application needs to use an external event or a timer to
+ * check the state of the ring buffer and refill it apropriately.
+ */
+int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
+{
+       assert(pcm && params);
+       
+       /* make sure non-blocking mode is enabled */
+       if (!(pcm->mode & SND_PCM_NONBLOCK))
+               return -EINVAL;
+       
+       if (!val)
+               params->flags |= SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP;
+       else
+               params->flags &= ~SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP;
+       return snd_pcm_hw_refine(pcm, params);
+}
+
+/**
+ * \brief Extract period wakeup mask from a configuration space
+ * \param pcm PCM handle
+ * \param params Configuration space
+ * \param val overwritten with 0 = disabled, 1 = enabled period wakeups
+ * \return Zero 
+ */
+int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)
+{
+       assert(pcm && params && val);
+       *val = params->flags & SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP ? 0 : 1;
+       return 0;
+}
+
+/**
  * \brief Extract period time from a configuration space
  * \param params Configuration space
  * \param val Returned approximate period duration in us
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 2f6fcd2..38d9267 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -94,6 +94,7 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t;
 
 #define SND_PCM_HW_PARAMS_NORESAMPLE SNDRV_PCM_HW_PARAMS_NORESAMPLE
 #define SND_PCM_HW_PARAMS_EXPORT_BUFFER SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER
+#define SND_PCM_HW_PARAMS_NO_PERIOD_WAKEUP SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP
 
 #define SND_PCM_INFO_MONOTONIC	0x80000000
 
-- 
1.7.2.3

