[ALSA] PCM midlevel & PCM OSS - make procfs & OSS plugin code optional
[deliverable/linux.git] / sound / core / oss / pcm_plugin.c
CommitLineData
1da177e4
LT
1/*
2 * PCM Plug-In shared (kernel/library) code
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#if 0
24#define PLUGIN_DEBUG
25#endif
26
27#include <sound/driver.h>
21a3479a
JK
28
29#ifdef CONFIG_SND_PCM_OSS_PLUGINS
30
1da177e4
LT
31#include <linux/slab.h>
32#include <linux/time.h>
33#include <linux/vmalloc.h>
34#include <sound/core.h>
35#include <sound/pcm.h>
36#include <sound/pcm_params.h>
37#include "pcm_plugin.h"
38
39#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
40#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
41
6ac77bc1 42static int snd_pcm_plugin_src_channels_mask(struct snd_pcm_plugin *plugin,
47eaebfd
TI
43 unsigned long *dst_vmask,
44 unsigned long **src_vmask)
1da177e4 45{
47eaebfd
TI
46 unsigned long *vmask = plugin->src_vmask;
47 bitmap_copy(vmask, dst_vmask, plugin->src_format.channels);
1da177e4
LT
48 *src_vmask = vmask;
49 return 0;
50}
51
6ac77bc1 52static int snd_pcm_plugin_dst_channels_mask(struct snd_pcm_plugin *plugin,
47eaebfd
TI
53 unsigned long *src_vmask,
54 unsigned long **dst_vmask)
1da177e4 55{
47eaebfd
TI
56 unsigned long *vmask = plugin->dst_vmask;
57 bitmap_copy(vmask, src_vmask, plugin->dst_format.channels);
1da177e4
LT
58 *dst_vmask = vmask;
59 return 0;
60}
61
62/*
63 * because some cards might have rates "very close", we ignore
64 * all "resampling" requests within +-5%
65 */
66static int rate_match(unsigned int src_rate, unsigned int dst_rate)
67{
68 unsigned int low = (src_rate * 95) / 100;
69 unsigned int high = (src_rate * 105) / 100;
70 return dst_rate >= low && dst_rate <= high;
71}
72
6ac77bc1 73static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
1da177e4 74{
6ac77bc1 75 struct snd_pcm_plugin_format *format;
1da177e4
LT
76 ssize_t width;
77 size_t size;
78 unsigned int channel;
6ac77bc1 79 struct snd_pcm_plugin_channel *c;
1da177e4
LT
80
81 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
82 format = &plugin->src_format;
83 } else {
84 format = &plugin->dst_format;
85 }
86 if ((width = snd_pcm_format_physical_width(format->format)) < 0)
87 return width;
88 size = frames * format->channels * width;
89 snd_assert((size % 8) == 0, return -ENXIO);
90 size /= 8;
91 if (plugin->buf_frames < frames) {
92 vfree(plugin->buf);
93 plugin->buf = vmalloc(size);
94 plugin->buf_frames = frames;
95 }
96 if (!plugin->buf) {
97 plugin->buf_frames = 0;
98 return -ENOMEM;
99 }
100 c = plugin->buf_channels;
101 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
102 for (channel = 0; channel < format->channels; channel++, c++) {
103 c->frames = frames;
104 c->enabled = 1;
105 c->wanted = 0;
106 c->area.addr = plugin->buf;
107 c->area.first = channel * width;
108 c->area.step = format->channels * width;
109 }
110 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
111 snd_assert((size % format->channels) == 0,);
112 size /= format->channels;
113 for (channel = 0; channel < format->channels; channel++, c++) {
114 c->frames = frames;
115 c->enabled = 1;
116 c->wanted = 0;
117 c->area.addr = plugin->buf + (channel * size);
118 c->area.first = 0;
119 c->area.step = width;
120 }
121 } else
122 return -EINVAL;
123 return 0;
124}
125
6ac77bc1 126int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
1da177e4
LT
127{
128 int err;
129 snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
130 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
6ac77bc1 131 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
1da177e4
LT
132 while (plugin->next) {
133 if (plugin->dst_frames)
134 frames = plugin->dst_frames(plugin, frames);
135 snd_assert(frames > 0, return -ENXIO);
136 plugin = plugin->next;
137 err = snd_pcm_plugin_alloc(plugin, frames);
138 if (err < 0)
139 return err;
140 }
141 } else {
6ac77bc1 142 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
1da177e4
LT
143 while (plugin->prev) {
144 if (plugin->src_frames)
145 frames = plugin->src_frames(plugin, frames);
146 snd_assert(frames > 0, return -ENXIO);
147 plugin = plugin->prev;
148 err = snd_pcm_plugin_alloc(plugin, frames);
149 if (err < 0)
150 return err;
151 }
152 }
153 return 0;
154}
155
156
6ac77bc1 157snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
1da177e4 158 snd_pcm_uframes_t frames,
6ac77bc1 159 struct snd_pcm_plugin_channel **channels)
1da177e4
LT
160{
161 *channels = plugin->buf_channels;
162 return frames;
163}
164
6ac77bc1 165int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
1da177e4 166 const char *name,
6ac77bc1
TI
167 struct snd_pcm_plugin_format *src_format,
168 struct snd_pcm_plugin_format *dst_format,
1da177e4 169 size_t extra,
6ac77bc1 170 struct snd_pcm_plugin **ret)
1da177e4 171{
6ac77bc1 172 struct snd_pcm_plugin *plugin;
1da177e4
LT
173 unsigned int channels;
174
175 snd_assert(plug != NULL, return -ENXIO);
176 snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
ca2c0966 177 plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
1da177e4
LT
178 if (plugin == NULL)
179 return -ENOMEM;
180 plugin->name = name;
181 plugin->plug = plug;
182 plugin->stream = snd_pcm_plug_stream(plug);
183 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
184 plugin->src_format = *src_format;
185 plugin->src_width = snd_pcm_format_physical_width(src_format->format);
186 snd_assert(plugin->src_width > 0, );
187 plugin->dst_format = *dst_format;
188 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
189 snd_assert(plugin->dst_width > 0, );
190 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
191 channels = src_format->channels;
192 else
193 channels = dst_format->channels;
194 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL);
195 if (plugin->buf_channels == NULL) {
196 snd_pcm_plugin_free(plugin);
197 return -ENOMEM;
198 }
47eaebfd 199 plugin->src_vmask = bitmap_alloc(src_format->channels);
1da177e4
LT
200 if (plugin->src_vmask == NULL) {
201 snd_pcm_plugin_free(plugin);
202 return -ENOMEM;
203 }
47eaebfd 204 plugin->dst_vmask = bitmap_alloc(dst_format->channels);
1da177e4
LT
205 if (plugin->dst_vmask == NULL) {
206 snd_pcm_plugin_free(plugin);
207 return -ENOMEM;
208 }
209 plugin->client_channels = snd_pcm_plugin_client_channels;
210 plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
211 plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
212 *ret = plugin;
213 return 0;
214}
215
6ac77bc1 216int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
1da177e4
LT
217{
218 if (! plugin)
219 return 0;
220 if (plugin->private_free)
221 plugin->private_free(plugin);
222 kfree(plugin->buf_channels);
223 vfree(plugin->buf);
224 kfree(plugin->src_vmask);
225 kfree(plugin->dst_vmask);
226 kfree(plugin);
227 return 0;
228}
229
6ac77bc1 230snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
1da177e4 231{
6ac77bc1 232 struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
1da177e4
LT
233 int stream = snd_pcm_plug_stream(plug);
234
235 snd_assert(plug != NULL, return -ENXIO);
236 if (drv_frames == 0)
237 return 0;
238 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
239 plugin = snd_pcm_plug_last(plug);
240 while (plugin && drv_frames > 0) {
241 plugin_prev = plugin->prev;
242 if (plugin->src_frames)
243 drv_frames = plugin->src_frames(plugin, drv_frames);
244 plugin = plugin_prev;
245 }
246 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
247 plugin = snd_pcm_plug_first(plug);
248 while (plugin && drv_frames > 0) {
249 plugin_next = plugin->next;
250 if (plugin->dst_frames)
251 drv_frames = plugin->dst_frames(plugin, drv_frames);
252 plugin = plugin_next;
253 }
254 } else
255 snd_BUG();
256 return drv_frames;
257}
258
6ac77bc1 259snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
1da177e4 260{
6ac77bc1 261 struct snd_pcm_plugin *plugin, *plugin_prev, *plugin_next;
1da177e4
LT
262 snd_pcm_sframes_t frames;
263 int stream = snd_pcm_plug_stream(plug);
264
265 snd_assert(plug != NULL, return -ENXIO);
266 if (clt_frames == 0)
267 return 0;
268 frames = clt_frames;
269 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
270 plugin = snd_pcm_plug_first(plug);
271 while (plugin && frames > 0) {
272 plugin_next = plugin->next;
273 if (plugin->dst_frames) {
274 frames = plugin->dst_frames(plugin, frames);
275 if (frames < 0)
276 return frames;
277 }
278 plugin = plugin_next;
279 }
280 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
281 plugin = snd_pcm_plug_last(plug);
282 while (plugin) {
283 plugin_prev = plugin->prev;
284 if (plugin->src_frames) {
285 frames = plugin->src_frames(plugin, frames);
286 if (frames < 0)
287 return frames;
288 }
289 plugin = plugin_prev;
290 }
291 } else
292 snd_BUG();
293 return frames;
294}
295
6ac77bc1 296static int snd_pcm_plug_formats(struct snd_mask *mask, int format)
1da177e4 297{
6ac77bc1 298 struct snd_mask formats = *mask;
1da177e4
LT
299 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
300 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
301 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
302 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
303 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
304 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
305 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
306 snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
307
308 if (formats.bits[0] & (u32)linfmts)
309 formats.bits[0] |= (u32)linfmts;
310 if (formats.bits[1] & (u32)(linfmts >> 32))
311 formats.bits[1] |= (u32)(linfmts >> 32);
312 return snd_mask_test(&formats, format);
313}
314
315static int preferred_formats[] = {
316 SNDRV_PCM_FORMAT_S16_LE,
317 SNDRV_PCM_FORMAT_S16_BE,
318 SNDRV_PCM_FORMAT_U16_LE,
319 SNDRV_PCM_FORMAT_U16_BE,
320 SNDRV_PCM_FORMAT_S24_LE,
321 SNDRV_PCM_FORMAT_S24_BE,
322 SNDRV_PCM_FORMAT_U24_LE,
323 SNDRV_PCM_FORMAT_U24_BE,
324 SNDRV_PCM_FORMAT_S32_LE,
325 SNDRV_PCM_FORMAT_S32_BE,
326 SNDRV_PCM_FORMAT_U32_LE,
327 SNDRV_PCM_FORMAT_U32_BE,
328 SNDRV_PCM_FORMAT_S8,
329 SNDRV_PCM_FORMAT_U8
330};
331
6ac77bc1 332int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask)
1da177e4
LT
333{
334 if (snd_mask_test(format_mask, format))
335 return format;
336 if (! snd_pcm_plug_formats(format_mask, format))
337 return -EINVAL;
338 if (snd_pcm_format_linear(format)) {
339 int width = snd_pcm_format_width(format);
340 int unsignd = snd_pcm_format_unsigned(format);
341 int big = snd_pcm_format_big_endian(format);
342 int format1;
343 int wid, width1=width;
344 int dwidth1 = 8;
345 for (wid = 0; wid < 4; ++wid) {
346 int end, big1 = big;
347 for (end = 0; end < 2; ++end) {
348 int sgn, unsignd1 = unsignd;
349 for (sgn = 0; sgn < 2; ++sgn) {
350 format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
351 if (format1 >= 0 &&
352 snd_mask_test(format_mask, format1))
353 goto _found;
354 unsignd1 = !unsignd1;
355 }
356 big1 = !big1;
357 }
358 if (width1 == 32) {
359 dwidth1 = -dwidth1;
360 width1 = width;
361 }
362 width1 += dwidth1;
363 }
364 return -EINVAL;
365 _found:
366 return format1;
367 } else {
368 unsigned int i;
369 switch (format) {
370 case SNDRV_PCM_FORMAT_MU_LAW:
371 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
372 int format1 = preferred_formats[i];
373 if (snd_mask_test(format_mask, format1))
374 return format1;
375 }
376 default:
377 return -EINVAL;
378 }
379 }
380}
381
6ac77bc1
TI
382int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
383 struct snd_pcm_hw_params *params,
384 struct snd_pcm_hw_params *slave_params)
1da177e4 385{
6ac77bc1
TI
386 struct snd_pcm_plugin_format tmpformat;
387 struct snd_pcm_plugin_format dstformat;
388 struct snd_pcm_plugin_format srcformat;
1da177e4 389 int src_access, dst_access;
6ac77bc1 390 struct snd_pcm_plugin *plugin = NULL;
1da177e4
LT
391 int err;
392 int stream = snd_pcm_plug_stream(plug);
393 int slave_interleaved = (params_channels(slave_params) == 1 ||
394 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);
395
396 switch (stream) {
397 case SNDRV_PCM_STREAM_PLAYBACK:
398 dstformat.format = params_format(slave_params);
399 dstformat.rate = params_rate(slave_params);
400 dstformat.channels = params_channels(slave_params);
401 srcformat.format = params_format(params);
402 srcformat.rate = params_rate(params);
403 srcformat.channels = params_channels(params);
404 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
405 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
406 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
407 break;
408 case SNDRV_PCM_STREAM_CAPTURE:
409 dstformat.format = params_format(params);
410 dstformat.rate = params_rate(params);
411 dstformat.channels = params_channels(params);
412 srcformat.format = params_format(slave_params);
413 srcformat.rate = params_rate(slave_params);
414 srcformat.channels = params_channels(slave_params);
415 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
416 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
417 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
418 break;
419 default:
420 snd_BUG();
421 return -EINVAL;
422 }
423 tmpformat = srcformat;
424
425 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
426 srcformat.format,
427 srcformat.rate,
428 srcformat.channels);
429 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
430 dstformat.format,
431 dstformat.rate,
432 dstformat.channels);
433
434 /* Format change (linearization) */
435 if ((srcformat.format != dstformat.format ||
436 !rate_match(srcformat.rate, dstformat.rate) ||
437 srcformat.channels != dstformat.channels) &&
438 !snd_pcm_format_linear(srcformat.format)) {
439 if (snd_pcm_format_linear(dstformat.format))
440 tmpformat.format = dstformat.format;
441 else
442 tmpformat.format = SNDRV_PCM_FORMAT_S16;
443 switch (srcformat.format) {
444 case SNDRV_PCM_FORMAT_MU_LAW:
445 err = snd_pcm_plugin_build_mulaw(plug,
446 &srcformat, &tmpformat,
447 &plugin);
448 break;
449 default:
450 return -EINVAL;
451 }
452 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
453 if (err < 0)
454 return err;
455 err = snd_pcm_plugin_append(plugin);
456 if (err < 0) {
457 snd_pcm_plugin_free(plugin);
458 return err;
459 }
460 srcformat = tmpformat;
461 src_access = dst_access;
462 }
463
464 /* channels reduction */
465 if (srcformat.channels > dstformat.channels) {
466 int sv = srcformat.channels;
467 int dv = dstformat.channels;
6ac77bc1 468 int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
1da177e4
LT
469 if (ttable == NULL)
470 return -ENOMEM;
471#if 1
472 if (sv == 2 && dv == 1) {
473 ttable[0] = HALF;
474 ttable[1] = HALF;
475 } else
476#endif
477 {
478 int v;
479 for (v = 0; v < dv; ++v)
480 ttable[v * sv + v] = FULL;
481 }
482 tmpformat.channels = dstformat.channels;
483 if (rate_match(srcformat.rate, dstformat.rate) &&
484 snd_pcm_format_linear(dstformat.format))
485 tmpformat.format = dstformat.format;
486 err = snd_pcm_plugin_build_route(plug,
487 &srcformat, &tmpformat,
488 ttable, &plugin);
489 kfree(ttable);
490 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
491 if (err < 0) {
492 snd_pcm_plugin_free(plugin);
493 return err;
494 }
495 err = snd_pcm_plugin_append(plugin);
496 if (err < 0) {
497 snd_pcm_plugin_free(plugin);
498 return err;
499 }
500 srcformat = tmpformat;
501 src_access = dst_access;
502 }
503
504 /* rate resampling */
505 if (!rate_match(srcformat.rate, dstformat.rate)) {
506 tmpformat.rate = dstformat.rate;
507 if (srcformat.channels == dstformat.channels &&
508 snd_pcm_format_linear(dstformat.format))
509 tmpformat.format = dstformat.format;
510 err = snd_pcm_plugin_build_rate(plug,
511 &srcformat, &tmpformat,
512 &plugin);
513 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
514 if (err < 0) {
515 snd_pcm_plugin_free(plugin);
516 return err;
517 }
518 err = snd_pcm_plugin_append(plugin);
519 if (err < 0) {
520 snd_pcm_plugin_free(plugin);
521 return err;
522 }
523 srcformat = tmpformat;
524 src_access = dst_access;
525 }
526
527 /* channels extension */
528 if (srcformat.channels < dstformat.channels) {
529 int sv = srcformat.channels;
530 int dv = dstformat.channels;
6ac77bc1 531 int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
1da177e4
LT
532 if (ttable == NULL)
533 return -ENOMEM;
534#if 0
535 {
536 int v;
537 for (v = 0; v < sv; ++v)
538 ttable[v * sv + v] = FULL;
539 }
540#else
541 {
542 /* Playback is spreaded on all channels */
543 int vd, vs;
544 for (vd = 0, vs = 0; vd < dv; ++vd) {
545 ttable[vd * sv + vs] = FULL;
546 vs++;
547 if (vs == sv)
548 vs = 0;
549 }
550 }
551#endif
552 tmpformat.channels = dstformat.channels;
553 if (snd_pcm_format_linear(dstformat.format))
554 tmpformat.format = dstformat.format;
555 err = snd_pcm_plugin_build_route(plug,
556 &srcformat, &tmpformat,
557 ttable, &plugin);
558 kfree(ttable);
559 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
560 if (err < 0) {
561 snd_pcm_plugin_free(plugin);
562 return err;
563 }
564 err = snd_pcm_plugin_append(plugin);
565 if (err < 0) {
566 snd_pcm_plugin_free(plugin);
567 return err;
568 }
569 srcformat = tmpformat;
570 src_access = dst_access;
571 }
572
573 /* format change */
574 if (srcformat.format != dstformat.format) {
575 tmpformat.format = dstformat.format;
576 if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
577 err = snd_pcm_plugin_build_mulaw(plug,
578 &srcformat, &tmpformat,
579 &plugin);
580 }
581 else if (snd_pcm_format_linear(srcformat.format) &&
582 snd_pcm_format_linear(tmpformat.format)) {
583 err = snd_pcm_plugin_build_linear(plug,
584 &srcformat, &tmpformat,
585 &plugin);
586 }
587 else
588 return -EINVAL;
589 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
590 if (err < 0)
591 return err;
592 err = snd_pcm_plugin_append(plugin);
593 if (err < 0) {
594 snd_pcm_plugin_free(plugin);
595 return err;
596 }
597 srcformat = tmpformat;
598 src_access = dst_access;
599 }
600
601 /* de-interleave */
602 if (src_access != dst_access) {
603 err = snd_pcm_plugin_build_copy(plug,
604 &srcformat,
605 &tmpformat,
606 &plugin);
607 pdprintf("interleave change (copy: returns %i)\n", err);
608 if (err < 0)
609 return err;
610 err = snd_pcm_plugin_append(plugin);
611 if (err < 0) {
612 snd_pcm_plugin_free(plugin);
613 return err;
614 }
615 }
616
617 return 0;
618}
619
6ac77bc1 620snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug,
1da177e4
LT
621 char *buf,
622 snd_pcm_uframes_t count,
6ac77bc1 623 struct snd_pcm_plugin_channel **channels)
1da177e4 624{
6ac77bc1
TI
625 struct snd_pcm_plugin *plugin;
626 struct snd_pcm_plugin_channel *v;
627 struct snd_pcm_plugin_format *format;
1da177e4
LT
628 int width, nchannels, channel;
629 int stream = snd_pcm_plug_stream(plug);
630
631 snd_assert(buf != NULL, return -ENXIO);
632 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
633 plugin = snd_pcm_plug_first(plug);
634 format = &plugin->src_format;
635 } else {
636 plugin = snd_pcm_plug_last(plug);
637 format = &plugin->dst_format;
638 }
639 v = plugin->buf_channels;
640 *channels = v;
641 if ((width = snd_pcm_format_physical_width(format->format)) < 0)
642 return width;
643 nchannels = format->channels;
644 snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
645 for (channel = 0; channel < nchannels; channel++, v++) {
646 v->frames = count;
647 v->enabled = 1;
648 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE);
649 v->area.addr = buf;
650 v->area.first = channel * width;
651 v->area.step = nchannels * width;
652 }
653 return count;
654}
655
6ac77bc1 656static int snd_pcm_plug_playback_channels_mask(struct snd_pcm_substream *plug,
47eaebfd 657 unsigned long *client_vmask)
1da177e4 658{
6ac77bc1 659 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
1da177e4
LT
660 if (plugin == NULL) {
661 return 0;
662 } else {
663 int schannels = plugin->dst_format.channels;
47eaebfd
TI
664 DECLARE_BITMAP(bs, schannels);
665 unsigned long *srcmask;
666 unsigned long *dstmask = bs;
1da177e4 667 int err;
47eaebfd 668 bitmap_fill(dstmask, schannels);
94f19c9a 669
1da177e4
LT
670 while (1) {
671 err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
672 if (err < 0)
673 return err;
674 dstmask = srcmask;
675 if (plugin->prev == NULL)
676 break;
677 plugin = plugin->prev;
678 }
47eaebfd 679 bitmap_and(client_vmask, client_vmask, dstmask, plugin->src_format.channels);
1da177e4
LT
680 return 0;
681 }
682}
683
6ac77bc1
TI
684static int snd_pcm_plug_playback_disable_useless_channels(struct snd_pcm_substream *plug,
685 struct snd_pcm_plugin_channel *src_channels)
1da177e4 686{
6ac77bc1 687 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
1da177e4 688 unsigned int nchannels = plugin->src_format.channels;
47eaebfd
TI
689 DECLARE_BITMAP(bs, nchannels);
690 unsigned long *srcmask = bs;
1da177e4
LT
691 int err;
692 unsigned int channel;
693 for (channel = 0; channel < nchannels; channel++) {
694 if (src_channels[channel].enabled)
47eaebfd 695 set_bit(channel, srcmask);
1da177e4 696 else
47eaebfd 697 clear_bit(channel, srcmask);
1da177e4
LT
698 }
699 err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
700 if (err < 0)
701 return err;
702 for (channel = 0; channel < nchannels; channel++) {
47eaebfd 703 if (!test_bit(channel, srcmask))
1da177e4
LT
704 src_channels[channel].enabled = 0;
705 }
706 return 0;
707}
708
6ac77bc1
TI
709static int snd_pcm_plug_capture_disable_useless_channels(struct snd_pcm_substream *plug,
710 struct snd_pcm_plugin_channel *src_channels,
711 struct snd_pcm_plugin_channel *client_channels)
1da177e4 712{
6ac77bc1 713 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
1da177e4 714 unsigned int nchannels = plugin->dst_format.channels;
47eaebfd
TI
715 DECLARE_BITMAP(bs, nchannels);
716 unsigned long *dstmask = bs;
717 unsigned long *srcmask;
1da177e4
LT
718 int err;
719 unsigned int channel;
720 for (channel = 0; channel < nchannels; channel++) {
721 if (client_channels[channel].enabled)
47eaebfd 722 set_bit(channel, dstmask);
1da177e4 723 else
47eaebfd 724 clear_bit(channel, dstmask);
1da177e4
LT
725 }
726 while (plugin) {
727 err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
728 if (err < 0)
729 return err;
730 dstmask = srcmask;
731 plugin = plugin->prev;
732 }
733 plugin = snd_pcm_plug_first(plug);
734 nchannels = plugin->src_format.channels;
735 for (channel = 0; channel < nchannels; channel++) {
47eaebfd 736 if (!test_bit(channel, dstmask))
1da177e4
LT
737 src_channels[channel].enabled = 0;
738 }
739 return 0;
740}
741
6ac77bc1 742snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size)
1da177e4 743{
6ac77bc1
TI
744 struct snd_pcm_plugin *plugin, *next;
745 struct snd_pcm_plugin_channel *dst_channels;
1da177e4
LT
746 int err;
747 snd_pcm_sframes_t frames = size;
748
749 if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
750 return err;
751
752 plugin = snd_pcm_plug_first(plug);
753 while (plugin && frames > 0) {
754 if ((next = plugin->next) != NULL) {
755 snd_pcm_sframes_t frames1 = frames;
756 if (plugin->dst_frames)
757 frames1 = plugin->dst_frames(plugin, frames);
758 if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
759 return err;
760 }
761 if (err != frames1) {
762 frames = err;
763 if (plugin->src_frames)
764 frames = plugin->src_frames(plugin, frames1);
765 }
766 } else
767 dst_channels = NULL;
768 pdprintf("write plugin: %s, %li\n", plugin->name, frames);
769 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
770 return frames;
771 src_channels = dst_channels;
772 plugin = next;
773 }
774 return snd_pcm_plug_client_size(plug, frames);
775}
776
6ac77bc1 777snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size)
1da177e4 778{
6ac77bc1
TI
779 struct snd_pcm_plugin *plugin, *next;
780 struct snd_pcm_plugin_channel *src_channels, *dst_channels;
1da177e4
LT
781 snd_pcm_sframes_t frames = size;
782 int err;
783
784 frames = snd_pcm_plug_slave_size(plug, frames);
785 if (frames < 0)
786 return frames;
787
788 src_channels = NULL;
789 plugin = snd_pcm_plug_first(plug);
790 while (plugin && frames > 0) {
791 if ((next = plugin->next) != NULL) {
792 if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
793 return err;
794 }
795 frames = err;
796 if (!plugin->prev) {
797 if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0)
798 return err;
799 }
800 } else {
801 dst_channels = dst_channels_final;
802 }
803 pdprintf("read plugin: %s, %li\n", plugin->name, frames);
804 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
805 return frames;
806 plugin = next;
807 src_channels = dst_channels;
808 }
809 return frames;
810}
811
6ac77bc1 812int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
1da177e4
LT
813 size_t samples, int format)
814{
815 /* FIXME: sub byte resolution and odd dst_offset */
816 unsigned char *dst;
817 unsigned int dst_step;
818 int width;
819 const unsigned char *silence;
820 if (!dst_area->addr)
821 return 0;
822 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
823 width = snd_pcm_format_physical_width(format);
824 if (width <= 0)
825 return -EINVAL;
826 if (dst_area->step == (unsigned int) width && width >= 8)
827 return snd_pcm_format_set_silence(format, dst, samples);
828 silence = snd_pcm_format_silence_64(format);
829 if (! silence)
830 return -EINVAL;
831 dst_step = dst_area->step / 8;
832 if (width == 4) {
833 /* Ima ADPCM */
834 int dstbit = dst_area->first % 8;
835 int dstbit_step = dst_area->step % 8;
836 while (samples-- > 0) {
837 if (dstbit)
838 *dst &= 0xf0;
839 else
840 *dst &= 0x0f;
841 dst += dst_step;
842 dstbit += dstbit_step;
843 if (dstbit == 8) {
844 dst++;
845 dstbit = 0;
846 }
847 }
848 } else {
849 width /= 8;
850 while (samples-- > 0) {
851 memcpy(dst, silence, width);
852 dst += dst_step;
853 }
854 }
855 return 0;
856}
857
6ac77bc1
TI
858int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
859 const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
1da177e4
LT
860 size_t samples, int format)
861{
862 /* FIXME: sub byte resolution and odd dst_offset */
863 char *src, *dst;
864 int width;
865 int src_step, dst_step;
866 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
867 if (!src_area->addr)
868 return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
869 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
870 if (!dst_area->addr)
871 return 0;
872 width = snd_pcm_format_physical_width(format);
873 if (width <= 0)
874 return -EINVAL;
875 if (src_area->step == (unsigned int) width &&
876 dst_area->step == (unsigned int) width && width >= 8) {
877 size_t bytes = samples * width / 8;
878 memcpy(dst, src, bytes);
879 return 0;
880 }
881 src_step = src_area->step / 8;
882 dst_step = dst_area->step / 8;
883 if (width == 4) {
884 /* Ima ADPCM */
885 int srcbit = src_area->first % 8;
886 int srcbit_step = src_area->step % 8;
887 int dstbit = dst_area->first % 8;
888 int dstbit_step = dst_area->step % 8;
889 while (samples-- > 0) {
890 unsigned char srcval;
891 if (srcbit)
892 srcval = *src & 0x0f;
893 else
894 srcval = (*src & 0xf0) >> 4;
895 if (dstbit)
896 *dst = (*dst & 0xf0) | srcval;
897 else
898 *dst = (*dst & 0x0f) | (srcval << 4);
899 src += src_step;
900 srcbit += srcbit_step;
901 if (srcbit == 8) {
902 src++;
903 srcbit = 0;
904 }
905 dst += dst_step;
906 dstbit += dstbit_step;
907 if (dstbit == 8) {
908 dst++;
909 dstbit = 0;
910 }
911 }
912 } else {
913 width /= 8;
914 while (samples-- > 0) {
915 memcpy(dst, src, width);
916 src += src_step;
917 dst += dst_step;
918 }
919 }
920 return 0;
921}
21a3479a
JK
922
923#endif
This page took 0.142671 seconds and 5 git commands to generate.