1193640Sariff/*-
2193640Sariff * Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org>
3193640Sariff * All rights reserved.
4193640Sariff *
5193640Sariff * Redistribution and use in source and binary forms, with or without
6193640Sariff * modification, are permitted provided that the following conditions
7193640Sariff * are met:
8193640Sariff * 1. Redistributions of source code must retain the above copyright
9193640Sariff *    notice, this list of conditions and the following disclaimer.
10193640Sariff * 2. Redistributions in binary form must reproduce the above copyright
11193640Sariff *    notice, this list of conditions and the following disclaimer in the
12193640Sariff *    documentation and/or other materials provided with the distribution.
13193640Sariff *
14193640Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15193640Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16193640Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17193640Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18193640Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19193640Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20193640Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21193640Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22193640Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23193640Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24193640Sariff * SUCH DAMAGE.
25193640Sariff */
26193640Sariff
27193640Sariff/*
28193640Sariff * feeder_format: New generation of generic, any-to-any format converter, as
29193640Sariff *                long as the sample values can be read _and_ write.
30193640Sariff */
31193640Sariff
32193640Sariff#ifdef _KERNEL
33193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
34193640Sariff#include "opt_snd.h"
35193640Sariff#endif
36193640Sariff#include <dev/sound/pcm/sound.h>
37193640Sariff#include <dev/sound/pcm/pcm.h>
38193640Sariff#include <dev/sound/pcm/g711.h>
39193640Sariff#include <dev/sound/pcm/intpcm.h>
40193640Sariff#include "feeder_if.h"
41193640Sariff
42193640Sariff#define SND_USE_FXDIV
43193640Sariff#include "snd_fxdiv_gen.h"
44193640Sariff
45193640SariffSND_DECLARE_FILE("$FreeBSD$");
46193640Sariff#endif
47193640Sariff
48193640Sariff#define FEEDFORMAT_RESERVOIR	(SND_CHN_MAX * PCM_32_BPS)
49193640Sariff
50193640SariffINTPCM_DECLARE(intpcm_conv_tables)
51193640Sariff
52193640Sariffstruct feed_format_info {
53193640Sariff	uint32_t ibps, obps;
54193640Sariff	uint32_t ialign, oalign, channels;
55193640Sariff	intpcm_read_t *read;
56193640Sariff	intpcm_write_t *write;
57193640Sariff	uint8_t reservoir[FEEDFORMAT_RESERVOIR];
58193640Sariff};
59193640Sariff
60193640Sariff/*
61193640Sariff * dummy ac3/dts passthrough, etc.
62193640Sariff * XXX assume as s16le.
63193640Sariff */
64193640Sariffstatic __inline intpcm_t
65193640Sariffintpcm_read_null(uint8_t *src __unused)
66193640Sariff{
67193640Sariff
68193640Sariff	return (0);
69193640Sariff}
70193640Sariff
71193640Sariffstatic __inline void
72193640Sariffintpcm_write_null(uint8_t *dst, intpcm_t v __unused)
73193640Sariff{
74193640Sariff
75193640Sariff	_PCM_WRITE_S16_LE(dst, 0);
76193640Sariff}
77193640Sariff
78193640Sariff#define FEEDFORMAT_ENTRY(SIGN, BIT, ENDIAN)				\
79193640Sariff	{								\
80193640Sariff		AFMT_##SIGN##BIT##_##ENDIAN,				\
81193640Sariff		intpcm_read_##SIGN##BIT##ENDIAN,			\
82193640Sariff		intpcm_write_##SIGN##BIT##ENDIAN			\
83193640Sariff	}
84193640Sariff
85193640Sariffstatic const struct {
86193640Sariff	uint32_t format;
87193640Sariff	intpcm_read_t *read;
88193640Sariff	intpcm_write_t *write;
89193640Sariff} feed_format_ops[] = {
90193640Sariff	FEEDFORMAT_ENTRY(S,  8, NE),
91193640Sariff	FEEDFORMAT_ENTRY(S, 16, LE),
92193640Sariff	FEEDFORMAT_ENTRY(S, 24, LE),
93193640Sariff	FEEDFORMAT_ENTRY(S, 32, LE),
94193640Sariff	FEEDFORMAT_ENTRY(S, 16, BE),
95193640Sariff	FEEDFORMAT_ENTRY(S, 24, BE),
96193640Sariff	FEEDFORMAT_ENTRY(S, 32, BE),
97193640Sariff	FEEDFORMAT_ENTRY(U,  8, NE),
98193640Sariff	FEEDFORMAT_ENTRY(U, 16, LE),
99193640Sariff	FEEDFORMAT_ENTRY(U, 24, LE),
100193640Sariff	FEEDFORMAT_ENTRY(U, 32, LE),
101193640Sariff	FEEDFORMAT_ENTRY(U, 16, BE),
102193640Sariff	FEEDFORMAT_ENTRY(U, 24, BE),
103193640Sariff	FEEDFORMAT_ENTRY(U, 32, BE),
104193640Sariff	{
105193640Sariff		AFMT_MU_LAW,
106193640Sariff		intpcm_read_ulaw, intpcm_write_ulaw
107193640Sariff	},
108193640Sariff	{
109193640Sariff		AFMT_A_LAW,
110193640Sariff		intpcm_read_alaw, intpcm_write_alaw
111193640Sariff	},
112193640Sariff	{
113193640Sariff		AFMT_AC3,
114193640Sariff		intpcm_read_null, intpcm_write_null
115193640Sariff	}
116193640Sariff};
117193640Sariff
118193640Sariff#define FEEDFORMAT_TAB_SIZE						\
119193640Sariff	((int32_t)(sizeof(feed_format_ops) / sizeof(feed_format_ops[0])))
120193640Sariff
121193640Sariffstatic int
122193640Sarifffeed_format_init(struct pcm_feeder *f)
123193640Sariff{
124193640Sariff	struct feed_format_info *info;
125193640Sariff	intpcm_read_t *rd_op;
126193640Sariff	intpcm_write_t *wr_op;
127193640Sariff	int i;
128193640Sariff
129193640Sariff	if (f->desc->in == f->desc->out ||
130193640Sariff	    AFMT_CHANNEL(f->desc->in) != AFMT_CHANNEL(f->desc->out))
131193640Sariff		return (EINVAL);
132193640Sariff
133193640Sariff	rd_op = NULL;
134193640Sariff	wr_op = NULL;
135193640Sariff
136193640Sariff	for (i = 0; i < FEEDFORMAT_TAB_SIZE &&
137193640Sariff	    (rd_op == NULL || wr_op == NULL); i++) {
138193640Sariff		if (rd_op == NULL &&
139193640Sariff		    AFMT_ENCODING(f->desc->in) == feed_format_ops[i].format)
140193640Sariff			rd_op = feed_format_ops[i].read;
141193640Sariff		if (wr_op == NULL &&
142193640Sariff		    AFMT_ENCODING(f->desc->out) == feed_format_ops[i].format)
143193640Sariff			wr_op = feed_format_ops[i].write;
144193640Sariff	}
145193640Sariff
146193640Sariff	if (rd_op == NULL || wr_op == NULL) {
147193640Sariff		printf("%s(): failed to initialize io ops "
148193640Sariff		    "in=0x%08x out=0x%08x\n",
149193640Sariff		    __func__, f->desc->in, f->desc->out);
150193640Sariff		return (EINVAL);
151193640Sariff	}
152193640Sariff
153193640Sariff	info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO);
154193640Sariff	if (info == NULL)
155193640Sariff		return (ENOMEM);
156193640Sariff
157193640Sariff	info->channels = AFMT_CHANNEL(f->desc->in);
158193640Sariff
159193640Sariff	info->ibps = AFMT_BPS(f->desc->in);
160193640Sariff	info->ialign = info->ibps * info->channels;
161193640Sariff	info->read = rd_op;
162193640Sariff
163193640Sariff	info->obps = AFMT_BPS(f->desc->out);
164193640Sariff	info->oalign = info->obps * info->channels;
165193640Sariff	info->write = wr_op;
166193640Sariff
167193640Sariff	f->data = info;
168193640Sariff
169193640Sariff	return (0);
170193640Sariff}
171193640Sariff
172193640Sariffstatic int
173193640Sarifffeed_format_free(struct pcm_feeder *f)
174193640Sariff{
175193640Sariff	struct feed_format_info *info;
176193640Sariff
177193640Sariff	info = f->data;
178193640Sariff	if (info != NULL)
179193640Sariff		free(info, M_DEVBUF);
180193640Sariff
181193640Sariff	f->data = NULL;
182193640Sariff
183193640Sariff	return (0);
184193640Sariff}
185193640Sariff
186193640Sariffstatic int
187193640Sarifffeed_format_set(struct pcm_feeder *f, int what, int value)
188193640Sariff{
189193640Sariff	struct feed_format_info *info;
190193640Sariff
191193640Sariff	info = f->data;
192193640Sariff
193193640Sariff	switch (what) {
194193640Sariff	case FEEDFORMAT_CHANNELS:
195193640Sariff		if (value < SND_CHN_MIN || value > SND_CHN_MAX)
196193640Sariff			return (EINVAL);
197193640Sariff		info->channels = (uint32_t)value;
198193640Sariff		info->ialign = info->ibps * info->channels;
199193640Sariff		info->oalign = info->obps * info->channels;
200193640Sariff		break;
201193640Sariff	default:
202193640Sariff		return (EINVAL);
203193640Sariff		break;
204193640Sariff	}
205193640Sariff
206193640Sariff	return (0);
207193640Sariff}
208193640Sariff
209193640Sariffstatic int
210193640Sarifffeed_format_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
211193640Sariff    uint32_t count, void *source)
212193640Sariff{
213193640Sariff	struct feed_format_info *info;
214193640Sariff	intpcm_t v;
215193640Sariff	uint32_t j;
216193640Sariff	uint8_t *src, *dst;
217193640Sariff
218193640Sariff	info = f->data;
219193640Sariff	dst = b;
220193640Sariff	count = SND_FXROUND(count, info->oalign);
221193640Sariff
222193640Sariff	do {
223193640Sariff		if (count < info->oalign)
224193640Sariff			break;
225193640Sariff
226193640Sariff		if (count < info->ialign) {
227193640Sariff			src = info->reservoir;
228193640Sariff			j = info->ialign;
229193640Sariff		} else {
230193640Sariff			if (info->ialign == info->oalign)
231193640Sariff				j = count;
232193640Sariff			else if (info->ialign > info->oalign)
233193640Sariff				j = SND_FXROUND(count, info->ialign);
234193640Sariff			else
235193640Sariff				j = SND_FXDIV(count, info->oalign) *
236193640Sariff				    info->ialign;
237193640Sariff			src = dst + count - j;
238193640Sariff		}
239193640Sariff
240193640Sariff		j = SND_FXDIV(FEEDER_FEED(f->source, c, src, j, source),
241193640Sariff		    info->ialign);
242193640Sariff		if (j == 0)
243193640Sariff			break;
244193640Sariff
245193640Sariff		j *= info->channels;
246193640Sariff		count -= j * info->obps;
247193640Sariff
248193640Sariff		do {
249193640Sariff			v = info->read(src);
250193640Sariff			info->write(dst, v);
251193640Sariff			dst += info->obps;
252193640Sariff			src += info->ibps;
253193640Sariff		} while (--j != 0);
254193640Sariff
255193640Sariff	} while (count != 0);
256193640Sariff
257193640Sariff	return (dst - b);
258193640Sariff}
259193640Sariff
260193640Sariffstatic struct pcm_feederdesc feeder_format_desc[] = {
261193640Sariff	{ FEEDER_FORMAT, 0, 0, 0, 0 },
262193640Sariff	{ 0, 0, 0, 0, 0 }
263193640Sariff};
264193640Sariff
265193640Sariffstatic kobj_method_t feeder_format_methods[] = {
266193640Sariff	KOBJMETHOD(feeder_init,		feed_format_init),
267193640Sariff	KOBJMETHOD(feeder_free,		feed_format_free),
268193640Sariff	KOBJMETHOD(feeder_set,		feed_format_set),
269193640Sariff	KOBJMETHOD(feeder_feed,		feed_format_feed),
270193640Sariff	KOBJMETHOD_END
271193640Sariff};
272193640Sariff
273193640SariffFEEDER_DECLARE(feeder_format, NULL);
274193640Sariff
275193640Sariff/* Extern */
276193640Sariffintpcm_read_t *
277193640Sarifffeeder_format_read_op(uint32_t format)
278193640Sariff{
279193640Sariff	int i;
280193640Sariff
281193640Sariff	for (i = 0; i < FEEDFORMAT_TAB_SIZE; i++) {
282193640Sariff		if (AFMT_ENCODING(format) == feed_format_ops[i].format)
283193640Sariff			return (feed_format_ops[i].read);
284193640Sariff	}
285193640Sariff
286193640Sariff	return (NULL);
287193640Sariff}
288193640Sariff
289193640Sariffintpcm_write_t *
290193640Sarifffeeder_format_write_op(uint32_t format)
291193640Sariff{
292193640Sariff	int i;
293193640Sariff
294193640Sariff	for (i = 0; i < FEEDFORMAT_TAB_SIZE; i++) {
295193640Sariff		if (AFMT_ENCODING(format) == feed_format_ops[i].format)
296193640Sariff			return (feed_format_ops[i].write);
297193640Sariff	}
298193640Sariff
299193640Sariff	return (NULL);
300193640Sariff}
301