aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/oss/linear.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/oss/linear.c')
-rw-r--r--sound/core/oss/linear.c91
1 files changed, 52 insertions, 39 deletions
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index 5b1bcdc647..06f96a3e86 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Linear conversion Plug-In 2 * Linear conversion Plug-In
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>, 3 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>,
4 * Abramo Bagnara <abramo@alsa-project.org> 4 * Abramo Bagnara <abramo@alsa-project.org>
5 * 5 *
6 * 6 *
@@ -21,9 +21,6 @@
21 */ 21 */
22 22
23#include <sound/driver.h> 23#include <sound/driver.h>
24
25#ifdef CONFIG_SND_PCM_OSS_PLUGINS
26
27#include <linux/time.h> 24#include <linux/time.h>
28#include <sound/core.h> 25#include <sound/core.h>
29#include <sound/pcm.h> 26#include <sound/pcm.h>
@@ -34,19 +31,34 @@
34 */ 31 */
35 32
36struct linear_priv { 33struct linear_priv {
37 int conv; 34 int cvt_endian; /* need endian conversion? */
35 unsigned int src_ofs; /* byte offset in source format */
36 unsigned int dst_ofs; /* byte soffset in destination format */
37 unsigned int copy_ofs; /* byte offset in temporary u32 data */
38 unsigned int dst_bytes; /* byte size of destination format */
39 unsigned int copy_bytes; /* bytes to copy per conversion */
40 unsigned int flip; /* MSB flip for signeness, done after endian conv */
38}; 41};
39 42
43static inline void do_convert(struct linear_priv *data,
44 unsigned char *dst, unsigned char *src)
45{
46 unsigned int tmp = 0;
47 unsigned char *p = (unsigned char *)&tmp;
48
49 memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes);
50 if (data->cvt_endian)
51 tmp = swab32(tmp);
52 tmp ^= data->flip;
53 memcpy(dst, p + data->dst_ofs, data->dst_bytes);
54}
55
40static void convert(struct snd_pcm_plugin *plugin, 56static void convert(struct snd_pcm_plugin *plugin,
41 const struct snd_pcm_plugin_channel *src_channels, 57 const struct snd_pcm_plugin_channel *src_channels,
42 struct snd_pcm_plugin_channel *dst_channels, 58 struct snd_pcm_plugin_channel *dst_channels,
43 snd_pcm_uframes_t frames) 59 snd_pcm_uframes_t frames)
44{ 60{
45#define CONV_LABELS
46#include "plugin_ops.h"
47#undef CONV_LABELS
48 struct linear_priv *data = (struct linear_priv *)plugin->extra_data; 61 struct linear_priv *data = (struct linear_priv *)plugin->extra_data;
49 void *conv = conv_labels[data->conv];
50 int channel; 62 int channel;
51 int nchannels = plugin->src_format.channels; 63 int nchannels = plugin->src_format.channels;
52 for (channel = 0; channel < nchannels; ++channel) { 64 for (channel = 0; channel < nchannels; ++channel) {
@@ -67,11 +79,7 @@ static void convert(struct snd_pcm_plugin *plugin,
67 dst_step = dst_channels[channel].area.step / 8; 79 dst_step = dst_channels[channel].area.step / 8;
68 frames1 = frames; 80 frames1 = frames;
69 while (frames1-- > 0) { 81 while (frames1-- > 0) {
70 goto *conv; 82 do_convert(data, dst, src);
71#define CONV_END after
72#include "plugin_ops.h"
73#undef CONV_END
74 after:
75 src += src_step; 83 src += src_step;
76 dst += dst_step; 84 dst += dst_step;
77 } 85 }
@@ -106,29 +114,36 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
106 return frames; 114 return frames;
107} 115}
108 116
109static int conv_index(int src_format, int dst_format) 117static void init_data(struct linear_priv *data, int src_format, int dst_format)
110{ 118{
111 int src_endian, dst_endian, sign, src_width, dst_width; 119 int src_le, dst_le, src_bytes, dst_bytes;
112 120
113 sign = (snd_pcm_format_signed(src_format) != 121 src_bytes = snd_pcm_format_width(src_format) / 8;
114 snd_pcm_format_signed(dst_format)); 122 dst_bytes = snd_pcm_format_width(dst_format) / 8;
115#ifdef SNDRV_LITTLE_ENDIAN 123 src_le = snd_pcm_format_little_endian(src_format) > 0;
116 src_endian = snd_pcm_format_big_endian(src_format); 124 dst_le = snd_pcm_format_little_endian(dst_format) > 0;
117 dst_endian = snd_pcm_format_big_endian(dst_format); 125
118#else 126 data->dst_bytes = dst_bytes;
119 src_endian = snd_pcm_format_little_endian(src_format); 127 data->cvt_endian = src_le != dst_le;
120 dst_endian = snd_pcm_format_little_endian(dst_format); 128 data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes;
121#endif 129 if (src_le) {
122 130 data->copy_ofs = 4 - data->copy_bytes;
123 if (src_endian < 0) 131 data->src_ofs = src_bytes - data->copy_bytes;
124 src_endian = 0; 132 } else
125 if (dst_endian < 0) 133 data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 -
126 dst_endian = 0; 134 src_bytes;
127 135 if (dst_le)
128 src_width = snd_pcm_format_width(src_format) / 8 - 1; 136 data->dst_ofs = 4 - data->dst_bytes;
129 dst_width = snd_pcm_format_width(dst_format) / 8 - 1; 137 else
130 138 data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 -
131 return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; 139 dst_bytes;
140 if (snd_pcm_format_signed(src_format) !=
141 snd_pcm_format_signed(dst_format)) {
142 if (dst_le)
143 data->flip = cpu_to_le32(0x80000000);
144 else
145 data->flip = cpu_to_be32(0x80000000);
146 }
132} 147}
133 148
134int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, 149int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug,
@@ -154,10 +169,8 @@ int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug,
154 if (err < 0) 169 if (err < 0)
155 return err; 170 return err;
156 data = (struct linear_priv *)plugin->extra_data; 171 data = (struct linear_priv *)plugin->extra_data;
157 data->conv = conv_index(src_format->format, dst_format->format); 172 init_data(data, src_format->format, dst_format->format);
158 plugin->transfer = linear_transfer; 173 plugin->transfer = linear_transfer;
159 *r_plugin = plugin; 174 *r_plugin = plugin;
160 return 0; 175 return 0;
161} 176}
162
163#endif