From 7c99bd24bcf6852d55e90e0f42f7ac5ea8f14fbb Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 15 Nov 2010 10:43:13 +0100 Subject: [PATCH 06/10] support for period wakeup disabling Add API to disable period wakeups. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Clemens Ladisch --- include/pcm.h | 3 ++ include/sound/asound.h | 2 + src/pcm/pcm.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++- src/pcm/pcm_local.h | 3 ++ 4 files changed, 79 insertions(+), 1 deletions(-) diff --git a/include/pcm.h b/include/pcm.h index f3618c3..7243ffb 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -531,6 +531,7 @@ int snd_pcm_hw_params_can_resume(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params); +int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params); int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, unsigned int *rate_num, unsigned int *rate_den); @@ -626,6 +627,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..17dfe8f 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -278,6 +278,7 @@ 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 */ enum sndrv_pcm_state { SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ @@ -346,6 +347,7 @@ 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; diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index a49b5b9..f378779 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -726,8 +726,11 @@ 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) + return -EINVAL; pcm->mode &= ~SND_PCM_NONBLOCK; + } return 0; } @@ -3081,6 +3084,23 @@ int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params) } /** + * \brief Check if hardware can disable period wakeups + * \param params Configuration space + * \return Boolean value + * \retval 0 Hardware cannot disable period wakeups + * \retval 1 Hardware can disable period wakeups + */ +int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params) +{ + assert(params); + if (CHECK_SANITY(params->info == ~0U)) { + SNDMSG("invalid PCM info field"); + return 0; /* FIXME: should be a negative error? */ + } + return !!(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP); +} + +/** * \brief Get rate exact info from a configuration space * \param params Configuration space * \param rate_num Pointer to returned rate numerator @@ -4200,6 +4220,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 must be called only on devices where non-blocking mode is + * enabled. + * + * To check whether the hardware does support disabling period wakeups, call + * #snd_pcm_hw_params_can_disable_period_wakeup(). If the hardware does not + * support this mode, standard period wakeups will be generated. + * + * Even with disabled period wakeups, 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); + + if (!val) { + if (!(pcm->mode & SND_PCM_NONBLOCK)) + return -EINVAL; + 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 flag from a configuration space + * \param pcm PCM handle + * \param params Configuration space + * \param val 0 = disabled, 1 = enabled period wakeups + * \return Zero on success, otherwise a negative error code. + */ +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..2e901d5 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -91,9 +91,12 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t; #define SND_PCM_INFO_JOINT_DUPLEX SNDRV_PCM_INFO_JOINT_DUPLEX /** device can do a kind of synchronized start */ #define SND_PCM_INFO_SYNC_START SNDRV_PCM_INFO_SYNC_START +/** device can disable period wakeups */ +#define SND_PCM_INFO_NO_PERIOD_WAKEUP SNDRV_PCM_INFO_NO_PERIOD_WAKEUP #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.3.1