Re: [RFC] ASLA design, depth of code review and lack thereof

From: Takashi Iwai
Date: Tue Jun 08 2004 - 07:51:52 EST


At Mon, 7 Jun 2004 23:40:45 +0100,
viro@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx wrote:
>
> On Mon, Jun 07, 2004 at 03:14:06PM +0200, Takashi Iwai wrote:
> > > and return a pointer to a (8-element) row in array of patterns. Because
> > > callers end up truncating the result and then filling a large area with
> > > repeated copies. All we get from use of u_int64_t is extra PITA with
> > > endianness - memcpy from 1/2/4/8 element array is no less efficient than
> > > assignment from u8/u16/u32/u64.
> >
> > Is it true? If gcc really optmizes well like this, yes, surely we can
> > use memcpy for simplicity.
>
> __builtin_memcpy() is definitely smart enough for that: e.g. on x86 (and you
> don't get much more register-starved than that)
> void b(char *);
> void a(char *x, int count)
> {
> char buf[8];
> int i;
> b(buf);
> for (i = 0; i < count; i++) {
> __builtin_memcpy(x, buf, 8);
> x += 8;
> }
> }
> will result (with -O2, which is normal for kernel) in
> .L6:
> movl %ecx, (%ebx)
> movl %edx, 4(%ebx)
> addl $8, %ebx
> decl %eax
> jne .L6
> as the main loop, which gives you what you would get from use of u64.
> And yes, constant-sized memcpy() in the kernel will be expanded to
> __builtin_memcpy().

Thanks for the confirmation!

The patch below is a draft version for clean-up and optmization of
that ugly stuffs. The pattern width is checked before filling loop to
pass the constant to memcpy(). If compiler can optimize such a case
by itself, this becomes superfluous.


Takashi


--- linux/sound/core/pcm_misc.c 4 May 2004 15:01:38 -0000 1.11
+++ linux/sound/core/pcm_misc.c 8 Jun 2004 12:40:20 -0000
@@ -23,12 +23,169 @@
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
-#define bswap_16 swab16
-#define bswap_32 swab32
-#define bswap_64 swab64
#define SND_PCM_FORMAT_UNKNOWN (-1)
-#define snd_enum_to_int(v) (v)
-#define snd_int_to_enum(v) (v)
+
+struct pcm_format_data {
+ char width; /* bit width */
+ char phys; /* physical bit width */
+ char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
+ char signd; /* 0 = unsigned, 1 = signed, -1 = others */
+ unsigned char silence[8]; /* silence data to fill */
+};
+
+static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
+ [SNDRV_PCM_FORMAT_S8] = {
+ .width = 8, .phys = 8, .le = -1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U8] = {
+ .width = 8, .phys = 8, .le = -1, .signd = 0,
+ .silence = { 0x80 },
+ },
+ [SNDRV_PCM_FORMAT_S16_LE] = {
+ .width = 16, .phys = 16, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S16_BE] = {
+ .width = 16, .phys = 16, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U16_LE] = {
+ .width = 16, .phys = 16, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x80 },
+ },
+ [SNDRV_PCM_FORMAT_U16_BE] = {
+ .width = 16, .phys = 16, .le = 0, .signd = 0,
+ .silence = { 0x80, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_S24_LE] = {
+ .width = 24, .phys = 32, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S24_BE] = {
+ .width = 24, .phys = 32, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U24_LE] = {
+ .width = 24, .phys = 32, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x80 },
+ },
+ [SNDRV_PCM_FORMAT_U24_BE] = {
+ .width = 24, .phys = 32, .le = 0, .signd = 0,
+ .silence = { 0x80, 0x00, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_S32_LE] = {
+ .width = 32, .phys = 32, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S32_BE] = {
+ .width = 32, .phys = 32, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U32_LE] = {
+ .width = 32, .phys = 32, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x00, 0x80 },
+ },
+ [SNDRV_PCM_FORMAT_U32_BE] = {
+ .width = 32, .phys = 32, .le = 0, .signd = 0,
+ .silence = { 0x80, 0x00, 0x00, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_FLOAT_LE] = {
+ .width = 32, .phys = 32, .le = 1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_FLOAT_BE] = {
+ .width = 32, .phys = 32, .le = 0, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
+ .width = 64, .phys = 64, .le = 1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
+ .width = 64, .phys = 64, .le = 0, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
+ .width = 32, .phys = 32, .le = 1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
+ .width = 32, .phys = 32, .le = 0, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_MU_LAW] = {
+ .width = 8, .phys = 8, .le = -1, .signd = -1,
+ .silence = { 0x7f },
+ },
+ [SNDRV_PCM_FORMAT_A_LAW] = {
+ .width = 8, .phys = 8, .le = -1, .signd = -1,
+ .silence = { 0x55 },
+ },
+ [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
+ .width = 4, .phys = 4, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ /* FIXME: the following three formats are not defined properly yet */
+ [SNDRV_PCM_FORMAT_MPEG] = {
+ .le = -1, .signd = -1,
+ },
+ [SNDRV_PCM_FORMAT_GSM] = {
+ .le = -1, .signd = -1,
+ },
+ [SNDRV_PCM_FORMAT_SPECIAL] = {
+ .le = -1, .signd = -1,
+ },
+ [SNDRV_PCM_FORMAT_S24_3LE] = {
+ .width = 24, .phys = 24, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S24_3BE] = {
+ .width = 24, .phys = 24, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U24_3LE] = {
+ .width = 24, .phys = 24, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x80 },
+ },
+ [SNDRV_PCM_FORMAT_U24_3BE] = {
+ .width = 24, .phys = 24, .le = 0, .signd = 0,
+ .silence = { 0x80, 0x00, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_S20_3LE] = {
+ .width = 20, .phys = 24, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S20_3BE] = {
+ .width = 20, .phys = 24, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U20_3LE] = {
+ .width = 20, .phys = 24, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x08 },
+ },
+ [SNDRV_PCM_FORMAT_U20_3BE] = {
+ .width = 20, .phys = 24, .le = 0, .signd = 0,
+ .silence = { 0x08, 0x00, 0x00 },
+ },
+ [SNDRV_PCM_FORMAT_S18_3LE] = {
+ .width = 18, .phys = 24, .le = 1, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_S18_3BE] = {
+ .width = 18, .phys = 24, .le = 0, .signd = 1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_U18_3LE] = {
+ .width = 18, .phys = 24, .le = 1, .signd = 0,
+ .silence = { 0x00, 0x00, 0x02 },
+ },
+ [SNDRV_PCM_FORMAT_U18_3BE] = {
+ .width = 18, .phys = 24, .le = 0, .signd = 0,
+ .silence = { 0x02, 0x00, 0x00 },
+ },
+};
+

/**
* snd_pcm_format_signed - Check the PCM format is signed linear
@@ -39,38 +196,12 @@
*/
int snd_pcm_format_signed(snd_pcm_format_t format)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- return 1;
- case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_U16_LE:
- case SNDRV_PCM_FORMAT_U16_BE:
- case SNDRV_PCM_FORMAT_U24_LE:
- case SNDRV_PCM_FORMAT_U24_BE:
- case SNDRV_PCM_FORMAT_U32_LE:
- case SNDRV_PCM_FORMAT_U32_BE:
- case SNDRV_PCM_FORMAT_U24_3LE:
- case SNDRV_PCM_FORMAT_U24_3BE:
- case SNDRV_PCM_FORMAT_U20_3LE:
- case SNDRV_PCM_FORMAT_U20_3BE:
- case SNDRV_PCM_FORMAT_U18_3LE:
- case SNDRV_PCM_FORMAT_U18_3BE:
- return 0;
- default:
+ int val;
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- }
+ if ((val = pcm_formats[format].signd) < 0)
+ return -EINVAL;
+ return val;
}

/**
@@ -110,42 +241,12 @@
*/
int snd_pcm_format_little_endian(snd_pcm_format_t format)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_U16_LE:
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_U24_LE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_U32_LE:
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- case SNDRV_PCM_FORMAT_FLOAT64_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_U24_3LE:
- case SNDRV_PCM_FORMAT_U20_3LE:
- case SNDRV_PCM_FORMAT_U18_3LE:
- return 1;
- case SNDRV_PCM_FORMAT_S16_BE:
- case SNDRV_PCM_FORMAT_U16_BE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_U24_BE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_U32_BE:
- case SNDRV_PCM_FORMAT_FLOAT_BE:
- case SNDRV_PCM_FORMAT_FLOAT64_BE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- case SNDRV_PCM_FORMAT_U24_3BE:
- case SNDRV_PCM_FORMAT_U20_3BE:
- case SNDRV_PCM_FORMAT_U18_3BE:
- return 0;
- default:
+ int val;
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- }
+ if ((val = pcm_formats[format].le) < 0)
+ return -EINVAL;
+ return val;
}

/**
@@ -190,55 +291,12 @@
*/
int snd_pcm_format_width(snd_pcm_format_t format)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_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:
- return 16;
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- case SNDRV_PCM_FORMAT_U18_3LE:
- case SNDRV_PCM_FORMAT_U18_3BE:
- return 18;
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_U20_3LE:
- case SNDRV_PCM_FORMAT_U20_3BE:
- return 20;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_U24_LE:
- case SNDRV_PCM_FORMAT_U24_BE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_U24_3LE:
- case SNDRV_PCM_FORMAT_U24_3BE:
- return 24;
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_U32_LE:
- case SNDRV_PCM_FORMAT_U32_BE:
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- case SNDRV_PCM_FORMAT_FLOAT_BE:
- return 32;
- case SNDRV_PCM_FORMAT_FLOAT64_LE:
- case SNDRV_PCM_FORMAT_FLOAT64_BE:
- return 64;
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
- return 32;
- case SNDRV_PCM_FORMAT_MU_LAW:
- case SNDRV_PCM_FORMAT_A_LAW:
- return 8;
- case SNDRV_PCM_FORMAT_IMA_ADPCM:
- return 4;
- default:
+ int val;
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- }
+ if ((val = pcm_formats[format].width) == 0)
+ return -EINVAL;
+ return val;
}

/**
@@ -250,52 +308,12 @@
*/
int snd_pcm_format_physical_width(snd_pcm_format_t format)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_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:
- return 16;
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- case SNDRV_PCM_FORMAT_U18_3LE:
- case SNDRV_PCM_FORMAT_U18_3BE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_U20_3LE:
- case SNDRV_PCM_FORMAT_U20_3BE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_U24_3LE:
- case SNDRV_PCM_FORMAT_U24_3BE:
- return 24;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_U24_LE:
- case SNDRV_PCM_FORMAT_U24_BE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_U32_LE:
- case SNDRV_PCM_FORMAT_U32_BE:
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- case SNDRV_PCM_FORMAT_FLOAT_BE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
- return 32;
- case SNDRV_PCM_FORMAT_FLOAT64_LE:
- case SNDRV_PCM_FORMAT_FLOAT64_BE:
- return 64;
- case SNDRV_PCM_FORMAT_MU_LAW:
- case SNDRV_PCM_FORMAT_A_LAW:
- return 8;
- case SNDRV_PCM_FORMAT_IMA_ADPCM:
- return 4;
- default:
+ int val;
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- }
+ if ((val = pcm_formats[format].phys) == 0)
+ return -EINVAL;
+ return val;
}

/**
@@ -307,216 +325,25 @@
*/
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_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:
- return samples * 2;
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- case SNDRV_PCM_FORMAT_U18_3LE:
- case SNDRV_PCM_FORMAT_U18_3BE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_U20_3LE:
- case SNDRV_PCM_FORMAT_U20_3BE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_U24_3LE:
- case SNDRV_PCM_FORMAT_U24_3BE:
- return samples * 3;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_U24_LE:
- case SNDRV_PCM_FORMAT_U24_BE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_U32_LE:
- case SNDRV_PCM_FORMAT_U32_BE:
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- case SNDRV_PCM_FORMAT_FLOAT_BE:
- return samples * 4;
- case SNDRV_PCM_FORMAT_FLOAT64_LE:
- case SNDRV_PCM_FORMAT_FLOAT64_BE:
- return samples * 8;
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
- return samples * 4;
- case SNDRV_PCM_FORMAT_MU_LAW:
- case SNDRV_PCM_FORMAT_A_LAW:
- return samples;
- case SNDRV_PCM_FORMAT_IMA_ADPCM:
- if (samples & 1)
- return -EINVAL;
- return samples / 2;
- default:
+ int phys_width = snd_pcm_format_physical_width(format);
+ if (phys_width < 0)
return -EINVAL;
- }
+ return samples * phys_width / 8;
}

/**
- * snd_pcm_format_silence_64 - return the silent data in 64bit integer
+ * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
* @format: the format to check
*
- * Returns the silent data in 64bit integer for the given format.
+ * Returns the format pattern to fill or NULL if error.
*/
-u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
+const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
{
- switch (snd_enum_to_int(format)) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_S24_3LE:
- case SNDRV_PCM_FORMAT_S24_3BE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
- return 0;
- case SNDRV_PCM_FORMAT_U8:
- return 0x8080808080808080ULL;
-#ifdef SNDRV_LITTLE_ENDIAN
- case SNDRV_PCM_FORMAT_U16_LE:
- return 0x8000800080008000ULL;
- case SNDRV_PCM_FORMAT_U24_LE:
- return 0x0080000000800000ULL;
- case SNDRV_PCM_FORMAT_U32_LE:
- return 0x8000000080000000ULL;
- case SNDRV_PCM_FORMAT_U16_BE:
- return 0x0080008000800080ULL;
- case SNDRV_PCM_FORMAT_U24_BE:
- return 0x0000800000008000ULL;
- case SNDRV_PCM_FORMAT_U32_BE:
- return 0x0000008000000080ULL;
- case SNDRV_PCM_FORMAT_U24_3LE:
- return 0x0000800000800000ULL;
- case SNDRV_PCM_FORMAT_U24_3BE:
- return 0x0080000080000080ULL;
- case SNDRV_PCM_FORMAT_U20_3LE:
- return 0x0000080000080000ULL;
- case SNDRV_PCM_FORMAT_U20_3BE:
- return 0x0008000008000008ULL;
- case SNDRV_PCM_FORMAT_U18_3LE:
- return 0x0000020000020000ULL;
- case SNDRV_PCM_FORMAT_U18_3BE:
- return 0x0002000002000002ULL;
-#else
- case SNDRV_PCM_FORMAT_U16_LE:
- return 0x0080008000800080ULL;
- case SNDRV_PCM_FORMAT_U24_LE:
- return 0x0000800000008000ULL;
- case SNDRV_PCM_FORMAT_U32_LE:
- return 0x0000008000000080ULL;
- case SNDRV_PCM_FORMAT_U16_BE:
- return 0x8000800080008000ULL;
- case SNDRV_PCM_FORMAT_U24_BE:
- return 0x0080000000800000ULL;
- case SNDRV_PCM_FORMAT_U32_BE:
- return 0x8000000080000000ULL;
- case SNDRV_PCM_FORMAT_U24_3LE:
- return 0x0080000080000080ULL;
- case SNDRV_PCM_FORMAT_U24_3BE:
- return 0x0000800000800000ULL;
- case SNDRV_PCM_FORMAT_U20_3LE:
- return 0x0008000008000008ULL;
- case SNDRV_PCM_FORMAT_U20_3BE:
- return 0x0000080000080000ULL;
- case SNDRV_PCM_FORMAT_U18_3LE:
- return 0x0002000002000002ULL;
- case SNDRV_PCM_FORMAT_U18_3BE:
- return 0x0000020000020000ULL;
-#endif
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- {
- union {
- float f;
- u_int32_t i;
- } u;
- u.f = 0.0;
-#ifdef SNDRV_LITTLE_ENDIAN
- return u.i;
-#else
- return bswap_32(u.i);
-#endif
- }
- case SNDRV_PCM_FORMAT_FLOAT64_LE:
- {
- union {
- double f;
- u_int64_t i;
- } u;
- u.f = 0.0;
-#ifdef SNDRV_LITTLE_ENDIAN
- return u.i;
-#else
- return bswap_64(u.i);
-#endif
- }
- case SNDRV_PCM_FORMAT_FLOAT_BE:
- {
- union {
- float f;
- u_int32_t i;
- } u;
- u.f = 0.0;
-#ifdef SNDRV_LITTLE_ENDIAN
- return bswap_32(u.i);
-#else
- return u.i;
-#endif
- }
- case SNDRV_PCM_FORMAT_FLOAT64_BE:
- {
- union {
- double f;
- u_int64_t i;
- } u;
- u.f = 0.0;
-#ifdef SNDRV_LITTLE_ENDIAN
- return bswap_64(u.i);
-#else
- return u.i;
-#endif
- }
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
- return 0;
- case SNDRV_PCM_FORMAT_MU_LAW:
- return 0x7f7f7f7f7f7f7f7fULL;
- case SNDRV_PCM_FORMAT_A_LAW:
- return 0x5555555555555555ULL;
- case SNDRV_PCM_FORMAT_IMA_ADPCM: /* special case */
- case SNDRV_PCM_FORMAT_MPEG:
- case SNDRV_PCM_FORMAT_GSM:
- case SNDRV_PCM_FORMAT_SPECIAL:
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format)
-{
- return (u_int32_t)snd_pcm_format_silence_64(format);
-}
-
-u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format)
-{
- return (u_int16_t)snd_pcm_format_silence_64(format);
-}
-
-u_int8_t snd_pcm_format_silence(snd_pcm_format_t format)
-{
- return (u_int8_t)snd_pcm_format_silence_64(format);
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ return NULL;
+ if (! pcm_formats[format].phys)
+ return NULL;
+ return pcm_formats[format].silence;
}

/**
@@ -531,99 +358,73 @@
*/
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
{
+ int width;
+ unsigned char *dst, *pat;
+
+ if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ return -EINVAL;
if (samples == 0)
return 0;
- switch (snd_pcm_format_width(format)) {
- case 4: {
- u_int8_t silence = snd_pcm_format_silence_64(format);
- unsigned int samples1;
- if (samples % 2 != 0)
- return -EINVAL;
- samples1 = samples / 2;
- memset(data, silence, samples1);
- break;
+ width = pcm_formats[format].phys; /* physical width */
+ pat = pcm_formats[format].silence;
+ if (! width)
+ return -EINVAL;
+ /* signed or 1 byte data */
+ if (pcm_formats[format].signd == 1 || width <= 8) {
+ unsigned int bytes = samples * width / 8;
+ memset(data, *pat, bytes);
+ return 0;
}
- case 8: {
- u_int8_t silence = snd_pcm_format_silence_64(format);
- memset(data, silence, samples);
- break;
+ /* non-zero samples, fill using a loop */
+ width /= 8;
+ dst = data;
+#if 0
+ while (samples--) {
+ memcpy(dst, pat, width);
+ dst += width;
}
- case 16: {
- u_int16_t silence = snd_pcm_format_silence_64(format);
- if (! silence)
- memset(data, 0, samples * 2);
- else {
- u_int16_t *data16 = data;
- while (samples-- > 0)
- *data16++ = silence;
+#else
+ /* a bit optimization for constant width */
+ switch (width) {
+ case 2:
+ while (samples--) {
+ memcpy(dst, pat, 2);
+ dst += 2;
}
break;
- }
- case 24: {
- u_int32_t silence = snd_pcm_format_silence_64(format);
- if (! silence)
- memset(data, 0, samples * 3);
- else {
- while (samples-- > 0) {
- u_int8_t *data8 = data;
-#ifdef SNDRV_LITTLE_ENDIAN
- *data8++ = silence >> 0;
- *data8++ = silence >> 8;
- *data8++ = silence >> 16;
-#else
- *data8++ = silence >> 16;
- *data8++ = silence >> 8;
- *data8++ = silence >> 0;
-#endif
- }
+ case 3:
+ while (samples--) {
+ memcpy(dst, pat, 3);
+ dst += 3;
}
break;
- }
- case 32: {
- u_int32_t silence = snd_pcm_format_silence_64(format);
- if (! silence)
- memset(data, 0, samples * 4);
- else {
- u_int32_t *data32 = data;
- while (samples-- > 0)
- *data32++ = silence;
+ case 4:
+ while (samples--) {
+ memcpy(dst, pat, 4);
+ dst += 4;
}
break;
- }
- case 64: {
- u_int64_t silence = snd_pcm_format_silence_64(format);
- if (! silence)
- memset(data, 0, samples * 8);
- else {
- u_int64_t *data64 = data;
- while (samples-- > 0)
- *data64++ = silence;
+ case 8:
+ while (samples--) {
+ memcpy(dst, pat, 8);
+ dst += 8;
}
break;
}
- default:
- return -EINVAL;
- }
+#endif
return 0;
}

-static int linear_formats[4*2*2] = {
- SNDRV_PCM_FORMAT_S8,
- SNDRV_PCM_FORMAT_S8,
- SNDRV_PCM_FORMAT_U8,
- SNDRV_PCM_FORMAT_U8,
- SNDRV_PCM_FORMAT_S16_LE,
- SNDRV_PCM_FORMAT_S16_BE,
- SNDRV_PCM_FORMAT_U16_LE,
- SNDRV_PCM_FORMAT_U16_BE,
- SNDRV_PCM_FORMAT_S24_LE,
- SNDRV_PCM_FORMAT_S24_BE,
- SNDRV_PCM_FORMAT_U24_LE,
- SNDRV_PCM_FORMAT_U24_BE,
- SNDRV_PCM_FORMAT_S32_LE,
- SNDRV_PCM_FORMAT_S32_BE,
- SNDRV_PCM_FORMAT_U32_LE,
- SNDRV_PCM_FORMAT_U32_BE
+/* [width][unsigned][bigendian] */
+static int linear_formats[4][2][2] = {
+ {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
+ { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}},
+ {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE},
+ {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}},
+ {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE},
+ {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}},
+ {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE},
+ {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}}
};

/**
@@ -636,23 +437,12 @@
*/
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
{
- switch (width) {
- case 8:
- width = 0;
- break;
- case 16:
- width = 1;
- break;
- case 24:
- width = 2;
- break;
- case 32:
- width = 3;
- break;
- default:
+ if (width & 7)
return SND_PCM_FORMAT_UNKNOWN;
- }
- return snd_int_to_enum(((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian]);
+ width = (width / 8) - 1;
+ if (width < 0 || width >= 4)
+ return SND_PCM_FORMAT_UNKNOWN;
+ return linear_formats[width][!!unsignd][!!big_endian];
}

/**
--- linux/include/sound/pcm.h 19 Mar 2004 20:13:58 -0000 1.41
+++ linux/include/sound/pcm.h 8 Jun 2004 10:42:00 -0000
@@ -851,7 +851,7 @@
int snd_pcm_format_big_endian(snd_pcm_format_t format);
int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */
int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */
-u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format);
+const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
--- linux/sound/core/oss/pcm_plugin.c 6 Feb 2004 17:46:56 -0000 1.17
+++ linux/sound/core/oss/pcm_plugin.c 8 Jun 2004 12:25:36 -0000
@@ -846,41 +846,31 @@
size_t samples, int format)
{
/* FIXME: sub byte resolution and odd dst_offset */
- char *dst;
+ unsigned char *dst;
unsigned int dst_step;
int width;
- u_int64_t silence;
+ const unsigned char *silence;
if (!dst_area->addr)
return 0;
dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
width = snd_pcm_format_physical_width(format);
+ if (width <= 0)
+ return -EINVAL;
+ if (dst_area->step == (unsigned int) width && width >= 8)
+ return snd_pcm_format_set_silence(format, dst, samples);
silence = snd_pcm_format_silence_64(format);
- if (dst_area->step == (unsigned int) width) {
- size_t dwords = samples * width / 64;
- u_int64_t *dst64 = (u_int64_t *)dst;
-
- samples -= dwords * 64 / width;
- while (dwords-- > 0)
- *dst64++ = silence;
- if (samples == 0)
- return 0;
- dst = (char *)dst64;
- }
+ if (! silence)
+ return -EINVAL;
dst_step = dst_area->step / 8;
- switch (width) {
- case 4: {
- u_int8_t s0 = silence & 0xf0;
- u_int8_t s1 = silence & 0x0f;
+ if (width == 4) {
+ /* Ima ADPCM */
int dstbit = dst_area->first % 8;
int dstbit_step = dst_area->step % 8;
while (samples-- > 0) {
- if (dstbit) {
+ if (dstbit)
*dst &= 0xf0;
- *dst |= s1;
- } else {
+ else
*dst &= 0x0f;
- *dst |= s0;
- }
dst += dst_step;
dstbit += dstbit_step;
if (dstbit == 8) {
@@ -888,41 +878,12 @@
dstbit = 0;
}
}
- break;
- }
- case 8: {
- u_int8_t sil = silence;
- while (samples-- > 0) {
- *dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 16: {
- u_int16_t sil = silence;
- while (samples-- > 0) {
- *(u_int16_t*)dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 32: {
- u_int32_t sil = silence;
- while (samples-- > 0) {
- *(u_int32_t*)dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 64: {
+ } else {
+ width /= 8;
while (samples-- > 0) {
- *(u_int64_t*)dst = silence;
+ memcpy(dst, silence, width);
dst += dst_step;
}
- break;
- }
- default:
- snd_BUG();
}
return 0;
}
@@ -942,18 +903,18 @@
if (!dst_area->addr)
return 0;
width = snd_pcm_format_physical_width(format);
+ if (width <= 0)
+ return -EINVAL;
if (src_area->step == (unsigned int) width &&
- dst_area->step == (unsigned int) width) {
+ dst_area->step == (unsigned int) width && width >= 8) {
size_t bytes = samples * width / 8;
- samples -= bytes * 8 / width;
memcpy(dst, src, bytes);
- if (samples == 0)
- return 0;
+ return 0;
}
src_step = src_area->step / 8;
dst_step = dst_area->step / 8;
- switch (width) {
- case 4: {
+ if (width == 4) {
+ /* Ima ADPCM */
int srcbit = src_area->first % 8;
int srcbit_step = src_area->step % 8;
int dstbit = dst_area->first % 8;
@@ -963,12 +924,11 @@
if (srcbit)
srcval = *src & 0x0f;
else
- srcval = *src & 0xf0;
+ srcval = (*src & 0xf0) >> 4;
if (dstbit)
- *dst &= 0xf0;
+ *dst = (*dst & 0xf0) | srcval;
else
- *dst &= 0x0f;
- *dst |= srcval;
+ *dst = (*dst & 0x0f) | (srcval << 4);
src += src_step;
srcbit += srcbit_step;
if (srcbit == 8) {
@@ -982,42 +942,13 @@
dstbit = 0;
}
}
- break;
- }
- case 8: {
- while (samples-- > 0) {
- *dst = *src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- case 16: {
+ } else {
+ width /= 8;
while (samples-- > 0) {
- *(u_int16_t*)dst = *(u_int16_t*)src;
+ memcpy(dst, src, width);
src += src_step;
dst += dst_step;
}
- break;
- }
- case 32: {
- while (samples-- > 0) {
- *(u_int32_t*)dst = *(u_int32_t*)src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- case 64: {
- while (samples-- > 0) {
- *(u_int64_t*)dst = *(u_int64_t*)src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- default:
- snd_BUG();
}
return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/