From 4bbe1ddf89a5ba3ec30fe5980912d8bda3a3cbb2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Oct 2008 03:07:14 +0200 Subject: ALSA: Add extra delay count in PCM Added runtime->delay field to adjust the delayed samples for snd_pcm_delay(). Typically a hardware FIFO length is stored in this field, so that the extra delay between hwptr and applptr can be computed. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/sound/pcm.h') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c1729689161..267effddb07 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -270,6 +270,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ + snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ snd_pcm_access_t access; /* access mode */ -- cgit v1.2.3-70-g09d2 From 8bea869c5e56234990e6bad92a543437115bfc18 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 27 Apr 2009 09:44:40 +0200 Subject: ALSA: PCM midlevel: improve fifo_size handling Move the fifo_size assignment to hw->ioctl callback to allow lowlevel drivers overwrite the default behaviour. fifo_size is in frames not bytes as specified in asound.h and alsa-lib's documentation, but most hardware have fixed byte based FIFOs. Introduce internal SNDRV_PCM_INFO_FIFO_IN_FRAMES. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/asound.h | 1 + include/sound/pcm.h | 1 + sound/core/pcm_lib.c | 19 +++++++++++++++++++ sound/core/pcm_native.c | 15 ++++++++++++--- 4 files changed, 33 insertions(+), 3 deletions(-) (limited to 'include/sound/pcm.h') diff --git a/include/sound/asound.h b/include/sound/asound.h index 6add80fc251..82aed3f4753 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -255,6 +255,7 @@ typedef int __bitwise snd_pcm_subformat_t; #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_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ typedef int __bitwise snd_pcm_state_t; #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 267effddb07..8a69b5c1e1c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -98,6 +98,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_INFO 1 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 #define SNDRV_PCM_IOCTL1_GSTATE 3 +#define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d659995ac3a..adc2b0bd113 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1524,6 +1524,23 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream, return 0; } +static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + snd_pcm_format_t format; + int channels, width; + + params->fifo_size = substream->runtime->hw.fifo_size; + if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { + format = params_format(params); + channels = params_channels(params); + width = snd_pcm_format_physical_width(format); + params->fifo_size /= width * channels; + } + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1545,6 +1562,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: return snd_pcm_lib_ioctl_channel_info(substream, arg); + case SNDRV_PCM_IOCTL1_FIFO_SIZE: + return snd_pcm_lib_ioctl_fifo_size(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 45dc53fcfa2..84da3ba17c8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -312,9 +312,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) - params->info = hw->info; - if (!params->fifo_size) - params->fifo_size = hw->fifo_size; + params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + if (!params->fifo_size) { + if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && + snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == + snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { + changed = substream->ops->ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + if (params < 0) + return changed; + } + } params->rmask = 0; return 0; } -- cgit v1.2.3-70-g09d2 From 3f7440a6b771169e1f11fa582e53a4259b682809 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Jun 2009 17:40:04 +0200 Subject: ALSA: Clean up 64bit division functions Replace the house-made div64_32() with the standard div_u64*() functions. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 74 ----------------------------------------------- sound/core/oss/pcm_oss.c | 5 ++-- sound/core/pcm_lib.c | 3 +- sound/pci/rme9652/hdsp.c | 7 ++--- sound/pci/rme9652/hdspm.c | 4 +-- 5 files changed, 9 insertions(+), 84 deletions(-) (limited to 'include/sound/pcm.h') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c1729689161..0caf71e1694 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -486,80 +486,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream); void snd_pcm_vma_notify_data(void *client, void *data); int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); -#if BITS_PER_LONG >= 64 - -static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -{ - *rem = *n % div; - *n /= div; -} - -#elif defined(i386) - -static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -{ - u_int32_t low, high; - low = *n & 0xffffffff; - high = *n >> 32; - if (high) { - u_int32_t high1 = high % div; - high /= div; - asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1)); - *n = (u_int64_t)high << 32 | low; - } else { - *n = low / div; - *rem = low % div; - } -} -#else - -static inline void divl(u_int32_t high, u_int32_t low, - u_int32_t div, - u_int32_t *q, u_int32_t *r) -{ - u_int64_t n = (u_int64_t)high << 32 | low; - u_int64_t d = (u_int64_t)div << 31; - u_int32_t q1 = 0; - int c = 32; - while (n > 0xffffffffU) { - q1 <<= 1; - if (n >= d) { - n -= d; - q1 |= 1; - } - d >>= 1; - c--; - } - q1 <<= c; - if (n) { - low = n; - *q = q1 | (low / div); - *r = low % div; - } else { - *r = 0; - *q = q1; - } - return; -} - -static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -{ - u_int32_t low, high; - low = *n & 0xffffffff; - high = *n >> 32; - if (high) { - u_int32_t high1 = high % div; - u_int32_t low1 = low; - high /= div; - divl(high1, low1, div, &low, rem); - *n = (u_int64_t)high << 32 | low; - } else { - *n = low / div; - *rem = low % div; - } -} -#endif - /* * PCM library */ diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index dda000b9684..dbe406b8259 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -617,9 +618,7 @@ static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames) #else { u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; - u32 rem; - div64_32(&bsize, buffer_size, &rem); - return (long)bsize; + return div_u64(bsize, buffer_size); } #endif } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d659995ac3a..a7482874c45 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -452,7 +453,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, *r = 0; return UINT_MAX; } - div64_32(&n, c, r); + n = div_u64_rem(n, c, r); if (n >= UINT_MAX) { *r = 0; return UINT_MAX; diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 314e73531bd..bcfdbb5ebc4 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1047,7 +1048,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) { u64 n; - u32 r; if (rate >= 112000) rate /= 4; @@ -1055,7 +1055,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) rate /= 2; n = DDS_NUMERATOR; - div64_32(&n, rate, &r); + n = div_u64(n, rate); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS @@ -3097,7 +3097,6 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn static int hdsp_dds_offset(struct hdsp *hdsp) { u64 n; - u32 r; unsigned int dds_value = hdsp->dds_value; int system_sample_rate = hdsp->system_sample_rate; @@ -3109,7 +3108,7 @@ static int hdsp_dds_offset(struct hdsp *hdsp) * dds_value = n / rate * rate = n / dds_value */ - div64_32(&n, dds_value, &r); + n = div_u64(n, dds_value); if (system_sample_rate >= 112000) n *= 4; else if (system_sample_rate >= 56000) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bac2dc0c5d8..0dce331a2a3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -831,7 +832,6 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames) static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) { u64 n; - u32 r; if (rate >= 112000) rate /= 4; @@ -844,7 +844,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) */ /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ n = 110100480000000ULL; /* Value checked for AES32 and MADI */ - div64_32(&n, rate, &r); + n = div_u64(n, rate); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); hdspm_write(hdspm, HDSPM_freqReg, (u32)n); -- cgit v1.2.3-70-g09d2