feeder.c revision 65645
150724Scg/*
250724Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
350724Scg * All rights reserved.
450724Scg *
550724Scg * Redistribution and use in source and binary forms, with or without
650724Scg * modification, are permitted provided that the following conditions
750724Scg * are met:
850724Scg * 1. Redistributions of source code must retain the above copyright
950724Scg *    notice, this list of conditions and the following disclaimer.
1050724Scg * 2. Redistributions in binary form must reproduce the above copyright
1150724Scg *    notice, this list of conditions and the following disclaimer in the
1250724Scg *    documentation and/or other materials provided with the distribution.
1350724Scg *
1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450724Scg * SUCH DAMAGE.
2550724Scg *
2650733Speter * $FreeBSD: head/sys/dev/sound/pcm/feeder.c 65645 2000-09-09 21:24:03Z cg $
2750724Scg */
2850724Scg
2953465Scg#include <dev/sound/pcm/sound.h>
3050724Scg
3150724Scg#define FEEDBUFSZ	8192
3265645Scg#undef FEEDER_DEBUG
3350724Scg
3450724Scgstatic unsigned char ulaw_to_u8[] = {
3550724Scg     3,    7,   11,   15,   19,   23,   27,   31,
3650724Scg    35,   39,   43,   47,   51,   55,   59,   63,
3750724Scg    66,   68,   70,   72,   74,   76,   78,   80,
3850724Scg    82,   84,   86,   88,   90,   92,   94,   96,
3950724Scg    98,   99,  100,  101,  102,  103,  104,  105,
4050724Scg   106,  107,  108,  109,  110,  111,  112,  113,
4150724Scg   113,  114,  114,  115,  115,  116,  116,  117,
4250724Scg   117,  118,  118,  119,  119,  120,  120,  121,
4350724Scg   121,  121,  122,  122,  122,  122,  123,  123,
4450724Scg   123,  123,  124,  124,  124,  124,  125,  125,
4550724Scg   125,  125,  125,  125,  126,  126,  126,  126,
4650724Scg   126,  126,  126,  126,  127,  127,  127,  127,
4750724Scg   127,  127,  127,  127,  127,  127,  127,  127,
4850724Scg   128,  128,  128,  128,  128,  128,  128,  128,
4950724Scg   128,  128,  128,  128,  128,  128,  128,  128,
5050724Scg   128,  128,  128,  128,  128,  128,  128,  128,
5150724Scg   253,  249,  245,  241,  237,  233,  229,  225,
5250724Scg   221,  217,  213,  209,  205,  201,  197,  193,
5350724Scg   190,  188,  186,  184,  182,  180,  178,  176,
5450724Scg   174,  172,  170,  168,  166,  164,  162,  160,
5550724Scg   158,  157,  156,  155,  154,  153,  152,  151,
5650724Scg   150,  149,  148,  147,  146,  145,  144,  143,
5750724Scg   143,  142,  142,  141,  141,  140,  140,  139,
5850724Scg   139,  138,  138,  137,  137,  136,  136,  135,
5950724Scg   135,  135,  134,  134,  134,  134,  133,  133,
6050724Scg   133,  133,  132,  132,  132,  132,  131,  131,
6150724Scg   131,  131,  131,  131,  130,  130,  130,  130,
6250724Scg   130,  130,  130,  130,  129,  129,  129,  129,
6350724Scg   129,  129,  129,  129,  129,  129,  129,  129,
6450724Scg   128,  128,  128,  128,  128,  128,  128,  128,
6550724Scg   128,  128,  128,  128,  128,  128,  128,  128,
6650724Scg   128,  128,  128,  128,  128,  128,  128,  128,
6750724Scg};
6850724Scg
6950724Scgstatic unsigned char u8_to_ulaw[] = {
7050724Scg     0,    0,    0,    0,    0,    1,    1,    1,
7150724Scg     1,    2,    2,    2,    2,    3,    3,    3,
7250724Scg     3,    4,    4,    4,    4,    5,    5,    5,
7350724Scg     5,    6,    6,    6,    6,    7,    7,    7,
7450724Scg     7,    8,    8,    8,    8,    9,    9,    9,
7550724Scg     9,   10,   10,   10,   10,   11,   11,   11,
7650724Scg    11,   12,   12,   12,   12,   13,   13,   13,
7750724Scg    13,   14,   14,   14,   14,   15,   15,   15,
7850724Scg    15,   16,   16,   17,   17,   18,   18,   19,
7950724Scg    19,   20,   20,   21,   21,   22,   22,   23,
8050724Scg    23,   24,   24,   25,   25,   26,   26,   27,
8150724Scg    27,   28,   28,   29,   29,   30,   30,   31,
8250724Scg    31,   32,   33,   34,   35,   36,   37,   38,
8350724Scg    39,   40,   41,   42,   43,   44,   45,   46,
8450724Scg    47,   49,   51,   53,   55,   57,   59,   61,
8550724Scg    63,   66,   70,   74,   78,   84,   92,  104,
8650724Scg   254,  231,  219,  211,  205,  201,  197,  193,
8750724Scg   190,  188,  186,  184,  182,  180,  178,  176,
8850724Scg   175,  174,  173,  172,  171,  170,  169,  168,
8950724Scg   167,  166,  165,  164,  163,  162,  161,  160,
9050724Scg   159,  159,  158,  158,  157,  157,  156,  156,
9150724Scg   155,  155,  154,  154,  153,  153,  152,  152,
9250724Scg   151,  151,  150,  150,  149,  149,  148,  148,
9350724Scg   147,  147,  146,  146,  145,  145,  144,  144,
9450724Scg   143,  143,  143,  143,  142,  142,  142,  142,
9550724Scg   141,  141,  141,  141,  140,  140,  140,  140,
9650724Scg   139,  139,  139,  139,  138,  138,  138,  138,
9750724Scg   137,  137,  137,  137,  136,  136,  136,  136,
9850724Scg   135,  135,  135,  135,  134,  134,  134,  134,
9950724Scg   133,  133,  133,  133,  132,  132,  132,  132,
10050724Scg   131,  131,  131,  131,  130,  130,  130,  130,
10150724Scg   129,  129,  129,  129,  128,  128,  128,  128,
10250724Scg};
10350724Scg
10464881Scgstruct feedertab_entry {
10564881Scg	SLIST_ENTRY(feedertab_entry) link;
10664881Scg	pcm_feeder *feeder;
10764881Scg	struct pcm_feederdesc *desc;
10864881Scg
10964881Scg	int idx;
11064881Scg};
11164881Scgstatic SLIST_HEAD(, feedertab_entry) feedertab;
11264881Scg
11350724Scg/*****************************************************************************/
11450724Scg
11564881Scgvoid
11664881Scgfeeder_register(void *p)
11764881Scg{
11864881Scg	pcm_feeder *f = p;
11964881Scg	struct feedertab_entry *fte;
12064881Scg	static int feedercnt = 0;
12164881Scg	int i;
12264881Scg
12364881Scg	if (feedercnt == 0) {
12464881Scg		if (f->desc)
12564881Scg			panic("FIRST FEEDER NOT ROOT: %s\n", f->name);
12664881Scg		SLIST_INIT(&feedertab);
12764881Scg		fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT);
12864881Scg		fte->feeder = f;
12964881Scg		fte->desc = NULL;
13064881Scg		fte->idx = feedercnt;
13164881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
13264881Scg		feedercnt++;
13364881Scg		return;
13464881Scg	}
13564881Scg	/* printf("installing feeder: %s\n", f->name); */
13664881Scg
13764881Scg	i = 0;
13864881Scg	while ((feedercnt < MAXFEEDERS) && (f->desc[i].type > 0)) {
13964881Scg		fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT);
14064881Scg		fte->feeder = f;
14164881Scg		fte->desc = &f->desc[i];
14264881Scg		fte->idx = feedercnt;
14364881Scg		fte->desc->idx = feedercnt;
14464881Scg		SLIST_INSERT_HEAD(&feedertab, fte, link);
14564881Scg		i++;
14664881Scg	}
14764881Scg	feedercnt++;
14864881Scg	if (feedercnt >= MAXFEEDERS)
14964881Scg		printf("MAXFEEDERS exceeded\n");
15064881Scg}
15164881Scg
15264881Scg/*****************************************************************************/
15364881Scg
15450724Scgstatic int
15553205Scgfeed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream)
15650724Scg{
15764881Scg	int ret, s;
15864881Scg
15954155Scg	KASSERT(count, ("feed_root: count == 0"));
16053205Scg	count &= ~((1 << ch->align) - 1);
16154155Scg	KASSERT(count, ("feed_root: aligned count == 0"));
16264881Scg
16354155Scg	s = spltty();
16454155Scg	count = min(count, stream->uio_resid);
16554155Scg	if (count) {
16654155Scg		ret = uiomove(buffer, count, stream);
16754155Scg		KASSERT(ret == 0, ("feed_root: uiomove failed"));
16850923Scg	}
16954155Scg	splx(s);
17064881Scg
17164881Scg	return count;
17250724Scg}
17364881Scgstatic pcm_feeder feeder_root = { "root", 0, NULL, NULL, NULL, feed_root };
17464881ScgSYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root);
17550724Scg
17650724Scg/*****************************************************************************/
17750724Scg
17850724Scgstatic int
17964881Scgfeed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
18050724Scg{
18150724Scg	int i, j, k;
18264881Scg
18353205Scg	k = f->source->feed(f->source, c, b, count / 2, stream);
18450724Scg	j = k - 1;
18550724Scg	i = j * 2 + 1;
18650724Scg	while (i > 0 && j >= 0) {
18750724Scg		b[i--] = b[j--];
18850724Scg		b[i--] = 0;
18950724Scg	}
19050724Scg	return k * 2;
19150724Scg}
19250724Scg
19364881Scgstatic struct pcm_feederdesc desc_8to16le[] = {
19464881Scg	{FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0},
19564881Scg	{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
19664881Scg	{FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0},
19764881Scg	{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
19864881Scg	{0},
19964881Scg};
20064881Scgstatic pcm_feeder feeder_8to16le =
20164881Scg	{ "8to16le", 0, desc_8to16le, NULL, NULL, feed_8to16le };
20264881ScgSYSINIT(feeder_8to16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_8to16le);
20364881Scg
20450724Scg/*****************************************************************************/
20550724Scg
20650724Scgstatic int
20750724Scgfeed_16to8_init(pcm_feeder *f)
20850724Scg{
20950724Scg	f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT);
21050724Scg	return (f->data == NULL);
21150724Scg}
21250724Scg
21350724Scgstatic int
21450724Scgfeed_16to8_free(pcm_feeder *f)
21550724Scg{
21650724Scg	if (f->data) free(f->data, M_DEVBUF);
21750724Scg	f->data = NULL;
21850724Scg	return 0;
21950724Scg}
22050724Scg
22150724Scgstatic int
22264881Scgfeed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
22350724Scg{
22450724Scg	u_int32_t i = 0, toget = count * 2;
22550724Scg	int j = 1, k;
22664881Scg
22753205Scg	k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
22850724Scg	while (j < k) {
22950724Scg		b[i++] = ((u_int8_t *)f->data)[j];
23050724Scg		j += 2;
23150724Scg	}
23250724Scg	return i;
23350724Scg}
23450724Scg
23564881Scgstatic struct pcm_feederdesc desc_16leto8[] = {
23664881Scg	{FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0},
23764881Scg	{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
23864881Scg	{FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0},
23964881Scg	{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
24064881Scg	{0},
24164881Scg};
24264881Scgstatic pcm_feeder feeder_16leto8 =
24364881Scg	{ "16leto8", 1, desc_16leto8, feed_16to8_init, feed_16to8_free, feed_16leto8 };
24464881ScgSYSINIT(feeder_16leto8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_16leto8);
24564881Scg
24650724Scg/*****************************************************************************/
24750724Scg
24850724Scgstatic int
24953205Scgfeed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
25050724Scg{
25153205Scg	int i, j, k = f->source->feed(f->source, c, b, count / 2, stream);
25264881Scg
25350724Scg	j = k - 1;
25450724Scg	i = j * 2 + 1;
25550724Scg	while (i > 0 && j >= 0) {
25650724Scg		b[i--] = b[j];
25750724Scg		b[i--] = b[j];
25850724Scg		j--;
25950724Scg	}
26050724Scg	return k * 2;
26150724Scg}
26264881Scg
26364881Scgstatic struct pcm_feederdesc desc_monotostereo8[] = {
26464881Scg	{FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0},
26564881Scg	{FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0},
26664881Scg	{0},
26764881Scg};
26850724Scgstatic pcm_feeder feeder_monotostereo8 =
26964881Scg	{ "monotostereo8", 0, desc_monotostereo8, NULL, NULL, feed_monotostereo8 };
27064881ScgSYSINIT(feeder_monotostereo8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo8);
27150724Scg
27250724Scg/*****************************************************************************/
27350724Scg
27450724Scgstatic int
27565645Scgfeed_monotostereo16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
27665645Scg{
27765645Scg	int i, j, k = f->source->feed(f->source, c, b, count / 2, stream);
27865645Scg	u_int8_t x, y;
27965645Scg
28065645Scg	j = k - 1;
28165645Scg	i = j * 2 + 1;
28265645Scg	while (i > 3 && j >= 1) {
28365645Scg		x = b[j--];
28465645Scg		y = b[j--];
28565645Scg		b[i--] = x;
28665645Scg		b[i--] = y;
28765645Scg		b[i--] = x;
28865645Scg		b[i--] = y;
28965645Scg	}
29065645Scg	return k * 2;
29165645Scg}
29265645Scg
29365645Scgstatic struct pcm_feederdesc desc_monotostereo16[] = {
29465645Scg	{FEEDER_FMT, AFMT_U16_LE, AFMT_U16_LE | AFMT_STEREO, 0},
29565645Scg	{FEEDER_FMT, AFMT_S16_LE, AFMT_S16_LE | AFMT_STEREO, 0},
29665645Scg	{FEEDER_FMT, AFMT_U16_BE, AFMT_U16_BE | AFMT_STEREO, 0},
29765645Scg	{FEEDER_FMT, AFMT_S16_BE, AFMT_S16_BE | AFMT_STEREO, 0},
29865645Scg	{0},
29965645Scg};
30065645Scgstatic pcm_feeder feeder_monotostereo16 =
30165645Scg	{ "monotostereo16", 0, desc_monotostereo16, NULL, NULL, feed_monotostereo16 };
30265645ScgSYSINIT(feeder_monotostereo16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo16);
30365645Scg
30465645Scg/*****************************************************************************/
30565645Scg
30665645Scgstatic int
30750724Scgfeed_stereotomono8_init(pcm_feeder *f)
30850724Scg{
30950724Scg	f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT);
31050724Scg	return (f->data == NULL);
31150724Scg}
31250724Scg
31350724Scgstatic int
31450724Scgfeed_stereotomono8_free(pcm_feeder *f)
31550724Scg{
31650724Scg	if (f->data) free(f->data, M_DEVBUF);
31750724Scg	f->data = NULL;
31850724Scg	return 0;
31950724Scg}
32050724Scg
32150724Scgstatic int
32253205Scgfeed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
32350724Scg{
32450724Scg	u_int32_t i = 0, toget = count * 2;
32550724Scg	int j = 0, k;
32664881Scg
32753205Scg	k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
32850724Scg	while (j < k) {
32950724Scg		b[i++] = ((u_int8_t *)f->data)[j];
33050724Scg		j += 2;
33150724Scg	}
33250724Scg	return i;
33350724Scg}
33464881Scg
33564881Scgstatic struct pcm_feederdesc desc_stereotomono8[] = {
33664881Scg	{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0},
33764881Scg	{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0},
33864881Scg	{0},
33964881Scg};
34050724Scgstatic pcm_feeder feeder_stereotomono8 =
34164881Scg	{ "stereotomono8", 1, desc_stereotomono8, feed_stereotomono8_init, feed_stereotomono8_free, feed_stereotomono8 };
34264881ScgSYSINIT(feeder_stereotomono8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono8);
34350724Scg
34450724Scg/*****************************************************************************/
34550724Scg
34650724Scgstatic int
34765645Scgfeed_stereotomono16_init(pcm_feeder *f)
34865645Scg{
34965645Scg	f->data = malloc(FEEDBUFSZ, M_DEVBUF, M_NOWAIT);
35065645Scg	return (f->data == NULL);
35165645Scg}
35265645Scg
35365645Scgstatic int
35465645Scgfeed_stereotomono16_free(pcm_feeder *f)
35565645Scg{
35665645Scg	if (f->data) free(f->data, M_DEVBUF);
35765645Scg	f->data = NULL;
35865645Scg	return 0;
35965645Scg}
36065645Scg
36165645Scgstatic int
36265645Scgfeed_stereotomono16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
36365645Scg{
36465645Scg	u_int32_t i = 0, toget = count * 2;
36565645Scg	int j = 0, k;
36665645Scg
36765645Scg	k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
36865645Scg	while (j < k) {
36965645Scg		b[i++] = ((u_int8_t *)f->data)[j];
37065645Scg		b[i++] = ((u_int8_t *)f->data)[j + 1];
37165645Scg		j += 4;
37265645Scg	}
37365645Scg	return i;
37465645Scg}
37565645Scg
37665645Scgstatic struct pcm_feederdesc desc_stereotomono16[] = {
37765645Scg	{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE, 0},
37865645Scg	{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE, 0},
37965645Scg	{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE, 0},
38065645Scg	{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE, 0},
38165645Scg	{0},
38265645Scg};
38365645Scgstatic pcm_feeder feeder_stereotomono16 =
38465645Scg	{ "stereotomono16", 1, desc_stereotomono16, feed_stereotomono16_init, feed_stereotomono16_free, feed_stereotomono16 };
38565645ScgSYSINIT(feeder_stereotomono16, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono16);
38665645Scg
38765645Scg/*****************************************************************************/
38865645Scg
38965645Scgstatic int
39053205Scgfeed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
39150724Scg{
39250724Scg	u_int8_t t;
39353205Scg	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
39464881Scg
39550724Scg	while (i < j) {
39650724Scg		t = b[i];
39750724Scg		b[i] = b[i + 1];
39850724Scg		b[i + 1] = t;
39950724Scg		i += 2;
40050724Scg	}
40150923Scg	return i;
40250724Scg}
40350724Scg
40464881Scgstatic struct pcm_feederdesc desc_endian[] = {
40564881Scg	{FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0},
40664881Scg	{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
40764881Scg	{FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0},
40864881Scg	{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
40964881Scg	{FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0},
41064881Scg	{FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
41164881Scg	{FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0},
41264881Scg	{FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
41364881Scg	{0},
41464881Scg};
41564881Scgstatic pcm_feeder feeder_endian = { "endian", -1, desc_endian, NULL, NULL, feed_endian };
41664881ScgSYSINIT(feeder_endian, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_endian);
41764881Scg
41850724Scg/*****************************************************************************/
41950724Scg
42050724Scgstatic int
42153205Scgfeed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
42250724Scg{
42353205Scg	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
42450724Scg	int ssz = (int)f->data, ofs = ssz - 1;
42564881Scg
42650724Scg	while (i < j) {
42750724Scg		b[i + ofs] ^= 0x80;
42850724Scg		i += ssz;
42950724Scg	}
43050724Scg	return i;
43150724Scg}
43264881Scg
43364881Scgstatic struct pcm_feederdesc desc_sign8[] = {
43464881Scg	{FEEDER_FMT, AFMT_U8, AFMT_S8, 0},
43564881Scg	{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
43664881Scg	{FEEDER_FMT, AFMT_S8, AFMT_U8, 0},
43764881Scg	{FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
43864881Scg	{0},
43964881Scg};
44050724Scgstatic pcm_feeder feeder_sign8 =
44164881Scg	{ "sign8", 0, desc_sign8, NULL, NULL, feed_sign, (void *)1 };
44264881ScgSYSINIT(feeder_sign8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign8);
44350724Scg
44464881Scgstatic struct pcm_feederdesc desc_sign16le[] = {
44564881Scg	{FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0},
44664881Scg	{FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
44764881Scg	{FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0},
44864881Scg	{FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
44964881Scg	{0},
45064881Scg};
45164881Scgstatic pcm_feeder feeder_sign16le =
45264881Scg	{ "sign16le", -1, desc_sign16le, NULL, NULL, feed_sign, (void *)2 };
45364881ScgSYSINIT(feeder_sign16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign16le);
45464881Scg
45550724Scg/*****************************************************************************/
45650724Scg
45750724Scgstatic int
45853205Scgfeed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
45950724Scg{
46053205Scg	int i = 0, j = f->source->feed(f->source, c, b, count, stream);
46164881Scg
46250724Scg	while (i < j) {
46350724Scg		b[i] = ((u_int8_t *)f->data)[b[i]];
46450724Scg		i++;
46550724Scg	}
46650724Scg	return i;
46750724Scg}
46850724Scg
46964881Scgstatic struct pcm_feederdesc desc_ulawtou8[] = {
47064881Scg	{FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0},
47164881Scg	{FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
47264881Scg	{0},
47350724Scg};
47464881Scgstatic pcm_feeder feeder_ulawtou8 =
47564881Scg	{ "ulawtou8", 0, desc_ulawtou8, NULL, NULL, feed_table, ulaw_to_u8 };
47664881ScgSYSINIT(feeder_ulawtou8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_ulawtou8);
47750724Scg
47864881Scgstatic struct pcm_feederdesc desc_u8toulaw[] = {
47964881Scg	{FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0},
48064881Scg	{FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
48164881Scg	{0},
48250724Scg};
48364881Scgstatic pcm_feeder feeder_u8toulaw =
48464881Scg	{ "u8toulaw", 0, desc_u8toulaw, NULL, NULL, feed_table, u8_to_ulaw };
48564881ScgSYSINIT(feeder_u8toulaw, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_u8toulaw);
48650724Scg
48764881Scg/*****************************************************************************/
48850724Scg
48950724Scgstatic int
49064881Scgcmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
49150724Scg{
49264881Scg	return ((n->type == m->type) && (n->in == m->in) && (n->out == m->out) && (n->flags == m->flags));
49350724Scg}
49450724Scg
49564881Scgpcm_feeder *
49664881Scgfeeder_get(struct pcm_feederdesc *desc)
49750724Scg{
49864881Scg	struct feedertab_entry *fte;
49964881Scg
50064881Scg	SLIST_FOREACH(fte, &feedertab, link) {
50164881Scg		if ((fte->desc != NULL) && cmpdesc(desc, fte->desc))
50264881Scg			return fte->feeder;
50364881Scg	}
50464881Scg	return NULL;
50550724Scg}
50650724Scg
50764881Scgpcm_feeder *
50864881Scgfeeder_getroot()
50950724Scg{
51064881Scg	struct feedertab_entry *fte;
51150724Scg
51264881Scg	SLIST_FOREACH(fte, &feedertab, link) {
51364881Scg		if (fte->desc == NULL)
51464881Scg			return fte->feeder;
51564881Scg	}
51664881Scg	return NULL;
51750724Scg}
51850724Scg
51950724Scgint
52064881Scgchn_removefeeder(pcm_channel *c)
52150724Scg{
52264881Scg	pcm_feeder *f;
52350724Scg
52464881Scg	if (c->feeder->source == NULL)
52564881Scg		return -1;
52664881Scg	f = c->feeder->source;
52764881Scg	if (c->feeder->free)
52864881Scg		c->feeder->free(c->feeder);
52964881Scg	free(c->feeder, M_DEVBUF);
53064881Scg	c->feeder = f;
53164881Scg	return 0;
53250724Scg}
53350724Scg
53450724Scgstatic int
53564881Scgchainok(pcm_feeder *test, pcm_feeder *stop)
53650724Scg{
53764881Scg	u_int32_t visited[MAXFEEDERS / 32];
53864881Scg	u_int32_t idx, mask;
53964881Scg
54064881Scg	bzero(visited, sizeof(visited));
54164881Scg	while (test && (test != stop)) {
54264881Scg		idx = test->desc->idx;
54364881Scg		if (idx < 0)
54464881Scg			panic("bad idx %d", idx);
54564881Scg		if (idx >= MAXFEEDERS)
54664881Scg			panic("bad idx %d", idx);
54764881Scg		mask = 1 << (idx & 31);
54864881Scg		idx >>= 5;
54964881Scg		if (visited[idx] & mask)
55064881Scg			return 0;
55164881Scg		visited[idx] |= mask;
55264881Scg		test = test->source;
55364881Scg	}
55464881Scg	return 1;
55550724Scg}
55650724Scg
55764881Scgstatic pcm_feeder *
55864881Scgfeeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth)
55950724Scg{
56064881Scg	struct feedertab_entry *fte;
56164881Scg	pcm_feeder *try, *ret;
56264881Scg	struct pcm_feederdesc *trydesc;
56364881Scg
56464881Scg	/* printf("trying %s...\n", source->name); */
56564881Scg	if (fmtvalid(source->desc->out, to)) {
56664881Scg		/* printf("got it\n"); */
56764881Scg		return source;
56864881Scg	}
56964881Scg
57064881Scg	if (maxdepth < 0)
57164881Scg		return NULL;
57264881Scg
57364881Scg	try = malloc(sizeof(*try), M_DEVBUF, M_NOWAIT);
57464881Scg	trydesc = malloc(sizeof(*trydesc), M_DEVBUF, M_NOWAIT);
57564881Scg	trydesc->type = FEEDER_FMT;
57664881Scg	trydesc->in = source->desc->out;
57764881Scg	trydesc->out = 0;
57864881Scg	trydesc->flags = 0;
57964881Scg	trydesc->idx = -1;
58064881Scg
58164881Scg	SLIST_FOREACH(fte, &feedertab, link) {
58264881Scg		if ((fte->desc) && (fte->desc->in == source->desc->out)) {
58364881Scg			*try = *(fte->feeder);
58464881Scg			try->source = source;
58564881Scg			try->desc = trydesc;
58664881Scg			trydesc->out = fte->desc->out;
58764881Scg			trydesc->idx = fte->idx;
58864881Scg			ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL;
58964881Scg			if (ret != NULL)
59064881Scg				return ret;
59164881Scg		}
59264881Scg	}
59364881Scg	free(try, M_DEVBUF);
59464881Scg	free(trydesc, M_DEVBUF);
59564881Scg	/* printf("giving up %s...\n", source->name); */
59664881Scg	return NULL;
59750724Scg}
59850724Scg
59964881Scgu_int32_t
60064881Scgchn_feedchain(pcm_channel *c, u_int32_t *to)
60164881Scg{
60264881Scg	pcm_feeder *try, *stop;
60364881Scg	int max;
60464881Scg
60564881Scg	stop = c->feeder;
60664881Scg	try = NULL;
60764881Scg	max = 0;
60865645Scg	while (try == NULL && max < 8) {
60964881Scg		try = feeder_fmtchain(to, c->feeder, stop, max);
61065645Scg		max++;
61165645Scg	}
61264881Scg	if (try == NULL)
61364881Scg		return 0;
61464881Scg	c->feeder = try;
61564881Scg	c->align = 0;
61665645Scg#ifdef FEEDER_DEBUG
61765645Scg	printf("chain: ");
61865645Scg#endif
61964881Scg	while (try && (try != stop)) {
62065645Scg#ifdef FEEDER_DEBUG
62165645Scg		printf("%s [%d]", try->name, try->desc->idx);
62265645Scg		if (try->source)
62365645Scg			printf(" -> ");
62465645Scg#endif
62564881Scg		if (try->init)
62664881Scg			try->init(try);
62764881Scg		if (try->align > 0)
62864881Scg			c->align += try->align;
62964881Scg		else if (try->align < 0 && c->align < -try->align)
63064881Scg			c->align = -try->align;
63164881Scg		try = try->source;
63264881Scg	}
63365645Scg#ifdef FEEDER_DEBUG
63465645Scg	printf("%s [%d]\n", try->name, try->desc->idx);
63565645Scg#endif
63664881Scg	return c->feeder->desc->out;
63764881Scg}
638