1139749Simp/*-
2193640Sariff * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3193640Sariff * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
4193640Sariff * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
570291Scg * All rights reserved.
670291Scg *
770291Scg * Redistribution and use in source and binary forms, with or without
870291Scg * modification, are permitted provided that the following conditions
970291Scg * are met:
1070291Scg * 1. Redistributions of source code must retain the above copyright
1170291Scg *    notice, this list of conditions and the following disclaimer.
1270291Scg * 2. Redistributions in binary form must reproduce the above copyright
1370291Scg *    notice, this list of conditions and the following disclaimer in the
1470291Scg *    documentation and/or other materials provided with the distribution.
1570291Scg *
1670291Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1770291Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1870291Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1970291Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2070291Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2170291Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2270291Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2370291Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2470291Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2570291Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2670291Scg * SUCH DAMAGE.
2770291Scg */
2870291Scg
29193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
30193640Sariff#include "opt_snd.h"
31193640Sariff#endif
32193640Sariff
3370291Scg#include <dev/sound/pcm/sound.h>
3470291Scg
3574763Scg#include "feeder_if.h"
3674763Scg
37193640Sariff#define SND_USE_FXDIV
38193640Sariff#include "snd_fxdiv_gen.h"
39193640Sariff
4082180ScgSND_DECLARE_FILE("$FreeBSD$");
4182180Scg
4274763Scgstruct snd_dbuf *
43125136Struckmansndbuf_create(device_t dev, char *drv, char *desc, struct pcm_channel *channel)
4474763Scg{
4574763Scg	struct snd_dbuf *b;
4674763Scg
47111119Simp	b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
4874763Scg	snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
4989834Scg	b->dev = dev;
50125136Struckman	b->channel = channel;
5189834Scg
5274763Scg	return b;
5374763Scg}
5474763Scg
5574763Scgvoid
5674763Scgsndbuf_destroy(struct snd_dbuf *b)
5774763Scg{
58167773Sariff	sndbuf_free(b);
5974763Scg	free(b, M_DEVBUF);
6074763Scg}
6174763Scg
62111183Scognetbus_addr_t
63111183Scognetsndbuf_getbufaddr(struct snd_dbuf *buf)
64111183Scognet{
65111183Scognet	return (buf->buf_addr);
66111183Scognet}
67111183Scognet
6870291Scgstatic void
6970291Scgsndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
7070291Scg{
7174763Scg	struct snd_dbuf *b = (struct snd_dbuf *)arg;
7270291Scg
7370291Scg	if (bootverbose) {
74136531Syongari		device_printf(b->dev, "sndbuf_setmap %lx, %lx; ",
75136531Syongari		    (u_long)segs[0].ds_addr, (u_long)segs[0].ds_len);
76136531Syongari		printf("%p -> %lx\n", b->buf, (u_long)segs[0].ds_addr);
7770291Scg	}
78136531Syongari	if (error == 0)
79136531Syongari		b->buf_addr = segs[0].ds_addr;
80136531Syongari	else
81136531Syongari		b->buf_addr = 0;
8270291Scg}
8370291Scg
8470291Scg/*
8574763Scg * Allocate memory for DMA buffer. If the device does not use DMA transfers,
8674763Scg * the driver can call malloc(9) and sndbuf_setup() itself.
8770291Scg */
88111183Scognet
8970291Scgint
90168847Sariffsndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags,
91168847Sariff    unsigned int size)
9270291Scg{
93136531Syongari	int ret;
94136531Syongari
9570291Scg	b->dmatag = dmatag;
96219548Smarius	b->dmaflags = dmaflags | BUS_DMA_NOWAIT | BUS_DMA_COHERENT;
9770291Scg	b->maxsize = size;
9870291Scg	b->bufsize = b->maxsize;
99136531Syongari	b->buf_addr = 0;
100166393Sariff	b->flags |= SNDBUF_F_MANAGED;
101168847Sariff	if (bus_dmamem_alloc(b->dmatag, (void **)&b->buf, b->dmaflags,
102167773Sariff	    &b->dmamap)) {
103167773Sariff		sndbuf_free(b);
104136531Syongari		return (ENOMEM);
105167773Sariff	}
106136531Syongari	if (bus_dmamap_load(b->dmatag, b->dmamap, b->buf, b->maxsize,
107136531Syongari	    sndbuf_setmap, b, 0) != 0 || b->buf_addr == 0) {
108167773Sariff		sndbuf_free(b);
109136531Syongari		return (ENOMEM);
110136531Syongari	}
111136531Syongari
112136531Syongari	ret = sndbuf_resize(b, 2, b->maxsize / 2);
113136531Syongari	if (ret != 0)
114136531Syongari		sndbuf_free(b);
115167773Sariff
116136531Syongari	return (ret);
11770291Scg}
11870291Scg
11970291Scgint
12074763Scgsndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
12170291Scg{
122167773Sariff	b->flags &= ~SNDBUF_F_MANAGED;
123166393Sariff	if (buf)
124166393Sariff		b->flags |= SNDBUF_F_MANAGED;
12570291Scg	b->buf = buf;
12670291Scg	b->maxsize = size;
12770291Scg	b->bufsize = b->maxsize;
12870291Scg	return sndbuf_resize(b, 2, b->maxsize / 2);
12970291Scg}
13070291Scg
13170291Scgvoid
13274763Scgsndbuf_free(struct snd_dbuf *b)
13370291Scg{
13474763Scg	if (b->tmpbuf)
13574763Scg		free(b->tmpbuf, M_DEVBUF);
13674763Scg
137162588Snetchild	if (b->shadbuf)
138162588Snetchild		free(b->shadbuf, M_DEVBUF);
139167773Sariff
140167773Sariff	if (b->buf) {
141167773Sariff		if (b->flags & SNDBUF_F_MANAGED) {
142167773Sariff			if (b->dmamap)
143167773Sariff				bus_dmamap_unload(b->dmatag, b->dmamap);
144167773Sariff			if (b->dmatag)
145167773Sariff				bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
146167773Sariff		} else
147167773Sariff			free(b->buf, M_DEVBUF);
148167773Sariff	}
149167773Sariff
150167773Sariff	b->tmpbuf = NULL;
151162588Snetchild	b->shadbuf = NULL;
152167773Sariff	b->buf = NULL;
153162588Snetchild	b->sl = 0;
154167773Sariff	b->dmatag = NULL;
15577265Scg	b->dmamap = NULL;
15670291Scg}
15770291Scg
158170722Sariff#define SNDBUF_CACHE_SHIFT	5
159170722Sariff
16070291Scgint
16174763Scgsndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
16270291Scg{
163170722Sariff	unsigned int bufsize, allocsize;
164170722Sariff	u_int8_t *tmpbuf;
165125136Struckman
166193640Sariff	CHN_LOCK(b->channel);
16774763Scg	if (b->maxsize == 0)
168125136Struckman		goto out;
16970291Scg	if (blkcnt == 0)
17070291Scg		blkcnt = b->blkcnt;
17170291Scg	if (blksz == 0)
17270291Scg		blksz = b->blksz;
173170722Sariff	if (blkcnt < 2 || blksz < 16 || (blkcnt * blksz) > b->maxsize) {
174193640Sariff		CHN_UNLOCK(b->channel);
17570291Scg		return EINVAL;
176125136Struckman	}
17789834Scg	if (blkcnt == b->blkcnt && blksz == b->blksz)
178125136Struckman		goto out;
179125136Struckman
180170722Sariff	bufsize = blkcnt * blksz;
181170722Sariff
182170815Sariff	if (bufsize > b->allocsize ||
183170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
184170722Sariff		allocsize = round_page(bufsize);
185193640Sariff		CHN_UNLOCK(b->channel);
186170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
187193640Sariff		CHN_LOCK(b->channel);
188170722Sariff		if (snd_verbose > 3)
189170722Sariff			printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
190170722Sariff			    __func__, b, b->tmpbuf, tmpbuf,
191170722Sariff			    b->allocsize, allocsize, bufsize);
192170722Sariff		if (b->tmpbuf != NULL)
193170722Sariff			free(b->tmpbuf, M_DEVBUF);
194170722Sariff		b->tmpbuf = tmpbuf;
195170722Sariff		b->allocsize = allocsize;
196170722Sariff	} else if (snd_verbose > 3)
197170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
198170722Sariff		    __func__, b, b->allocsize, b->bufsize);
199170722Sariff
20070291Scg	b->blkcnt = blkcnt;
20170291Scg	b->blksz = blksz;
202170722Sariff	b->bufsize = bufsize;
203170722Sariff
20470291Scg	sndbuf_reset(b);
205125136Struckmanout:
206193640Sariff	CHN_UNLOCK(b->channel);
207125136Struckman	return 0;
20870291Scg}
20970291Scg
21074763Scgint
21174763Scgsndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
21274763Scg{
213170722Sariff        unsigned int bufsize, allocsize;
214170722Sariff	u_int8_t *buf, *tmpbuf, *shadbuf;
215107237Scg
21674763Scg	if (blkcnt < 2 || blksz < 16)
21774763Scg		return EINVAL;
21874763Scg
219107237Scg	bufsize = blksz * blkcnt;
22074763Scg
221170722Sariff	if (bufsize > b->allocsize ||
222170722Sariff	    bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
223170722Sariff		allocsize = round_page(bufsize);
224193640Sariff		CHN_UNLOCK(b->channel);
225170722Sariff		buf = malloc(allocsize, M_DEVBUF, M_WAITOK);
226170722Sariff		tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
227170722Sariff		shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
228193640Sariff		CHN_LOCK(b->channel);
229170722Sariff		if (b->buf != NULL)
230170722Sariff			free(b->buf, M_DEVBUF);
231170722Sariff		b->buf = buf;
232170722Sariff		if (b->tmpbuf != NULL)
233170722Sariff			free(b->tmpbuf, M_DEVBUF);
234170722Sariff		b->tmpbuf = tmpbuf;
235170722Sariff		if (b->shadbuf != NULL)
236170722Sariff			free(b->shadbuf, M_DEVBUF);
237170722Sariff		b->shadbuf = shadbuf;
238170722Sariff		if (snd_verbose > 3)
239170722Sariff			printf("%s(): b=%p %d -> %d [%d]\n",
240170722Sariff			    __func__, b, b->allocsize, allocsize, bufsize);
241170722Sariff		b->allocsize = allocsize;
242170722Sariff	} else if (snd_verbose > 3)
243170722Sariff		printf("%s(): b=%p %d [%d] NOCHANGE\n",
244170722Sariff		    __func__, b, b->allocsize, b->bufsize);
245162588Snetchild
246107237Scg	b->blkcnt = blkcnt;
247107237Scg	b->blksz = blksz;
248107237Scg	b->bufsize = bufsize;
249107237Scg	b->maxsize = bufsize;
250162588Snetchild	b->sl = bufsize;
251107237Scg
252125136Struckman	sndbuf_reset(b);
253125136Struckman
254170722Sariff	return 0;
25574763Scg}
25674763Scg
257162588Snetchild/**
258162588Snetchild * @brief Zero out space in buffer free area
259162588Snetchild *
260162588Snetchild * This function clears a chunk of @c length bytes in the buffer free area
261162588Snetchild * (i.e., where the next write will be placed).
262162588Snetchild *
263162588Snetchild * @param b		buffer context
264162588Snetchild * @param length	number of bytes to blank
265162588Snetchild */
26670291Scgvoid
26774763Scgsndbuf_clear(struct snd_dbuf *b, unsigned int length)
26870291Scg{
26970291Scg	int i;
27073768Scg	u_char data, *p;
27170291Scg
27270291Scg	if (length == 0)
27370291Scg		return;
27473768Scg	if (length > b->bufsize)
27573768Scg		length = b->bufsize;
27670291Scg
277164614Sariff	data = sndbuf_zerodata(b->fmt);
27870291Scg
27974763Scg	i = sndbuf_getfreeptr(b);
28074763Scg	p = sndbuf_getbuf(b);
28173768Scg	while (length > 0) {
28273768Scg		p[i] = data;
28373768Scg		length--;
28473768Scg		i++;
28573768Scg		if (i >= b->bufsize)
28670291Scg			i = 0;
28770291Scg	}
28870291Scg}
28970291Scg
290162588Snetchild/**
291162588Snetchild * @brief Zap buffer contents, resetting "ready area" fields
292162588Snetchild *
293162588Snetchild * @param b	buffer context
294162588Snetchild */
29570291Scgvoid
29677265Scgsndbuf_fillsilence(struct snd_dbuf *b)
29777265Scg{
298164614Sariff	if (b->bufsize > 0)
299164614Sariff		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
30077265Scg	b->rp = 0;
30177265Scg	b->rl = b->bufsize;
30277265Scg}
30377265Scg
304233164Smavvoid
305233164Smavsndbuf_fillsilence_rl(struct snd_dbuf *b, u_int rl)
306233164Smav{
307233164Smav	if (b->bufsize > 0)
308233164Smav		memset(sndbuf_getbuf(b), sndbuf_zerodata(b->fmt), b->bufsize);
309233164Smav	b->rp = 0;
310233164Smav	b->rl = min(b->bufsize, rl);
311233164Smav}
312233164Smav
313162588Snetchild/**
314162588Snetchild * @brief Reset buffer w/o flushing statistics
315162588Snetchild *
316162588Snetchild * This function just zeroes out buffer contents and sets the "ready length"
317162588Snetchild * to zero.  This was originally to facilitate minimal playback interruption
318162588Snetchild * (i.e., dropped samples) in SNDCTL_DSP_SILENCE/SKIP ioctls.
319162588Snetchild *
320162588Snetchild * @param b	buffer context
321162588Snetchild */
32277265Scgvoid
323162588Snetchildsndbuf_softreset(struct snd_dbuf *b)
324162588Snetchild{
325162588Snetchild	b->rl = 0;
326162588Snetchild	if (b->buf && b->bufsize > 0)
327162588Snetchild		sndbuf_clear(b, b->bufsize);
328162588Snetchild}
329162588Snetchild
330162588Snetchildvoid
33174763Scgsndbuf_reset(struct snd_dbuf *b)
33270291Scg{
33374763Scg	b->hp = 0;
33474763Scg	b->rp = 0;
33574763Scg	b->rl = 0;
33674763Scg	b->dl = 0;
33774763Scg	b->prev_total = 0;
33874763Scg	b->total = 0;
33974763Scg	b->xrun = 0;
34070291Scg	if (b->buf && b->bufsize > 0)
34170291Scg		sndbuf_clear(b, b->bufsize);
342162588Snetchild	sndbuf_clearshadow(b);
34370291Scg}
34470291Scg
34574763Scgu_int32_t
34674763Scgsndbuf_getfmt(struct snd_dbuf *b)
34774763Scg{
34874763Scg	return b->fmt;
34974763Scg}
35074763Scg
35170291Scgint
35274763Scgsndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
35370291Scg{
35470291Scg	b->fmt = fmt;
355193640Sariff	b->bps = AFMT_BPS(b->fmt);
356193640Sariff	b->align = AFMT_ALIGN(b->fmt);
357193640Sariff#if 0
358193640Sariff	b->bps = AFMT_CHANNEL(b->fmt);
359148606Snetchild	if (b->fmt & AFMT_16BIT)
360148606Snetchild		b->bps <<= 1;
361148606Snetchild	else if (b->fmt & AFMT_24BIT)
362148606Snetchild		b->bps *= 3;
363148606Snetchild	else if (b->fmt & AFMT_32BIT)
364148606Snetchild		b->bps <<= 2;
365193640Sariff#endif
36670291Scg	return 0;
36770291Scg}
36870291Scg
36974763Scgunsigned int
37074763Scgsndbuf_getspd(struct snd_dbuf *b)
37170291Scg{
37274763Scg	return b->spd;
37374763Scg}
37474763Scg
37574763Scgvoid
37674763Scgsndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
37774763Scg{
37874763Scg	b->spd = spd;
37974763Scg}
38074763Scg
38174763Scgunsigned int
38274763Scgsndbuf_getalign(struct snd_dbuf *b)
38374763Scg{
384193640Sariff	return (b->align);
38574763Scg}
38674763Scg
38774763Scgunsigned int
38874763Scgsndbuf_getblkcnt(struct snd_dbuf *b)
38974763Scg{
39074763Scg	return b->blkcnt;
39174763Scg}
39274763Scg
39374763Scgvoid
39474763Scgsndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
39574763Scg{
39674763Scg	b->blkcnt = blkcnt;
39774763Scg}
39874763Scg
39974763Scgunsigned int
40074763Scgsndbuf_getblksz(struct snd_dbuf *b)
40174763Scg{
40274763Scg	return b->blksz;
40374763Scg}
40474763Scg
40574763Scgvoid
40674763Scgsndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
40774763Scg{
40874763Scg	b->blksz = blksz;
40974763Scg}
41074763Scg
41174763Scgunsigned int
41274763Scgsndbuf_getbps(struct snd_dbuf *b)
41374763Scg{
41470291Scg	return b->bps;
41570291Scg}
41670291Scg
41770291Scgvoid *
41874763Scgsndbuf_getbuf(struct snd_dbuf *b)
41970291Scg{
42070291Scg	return b->buf;
42170291Scg}
42270291Scg
42374763Scgvoid *
42474763Scgsndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
42570291Scg{
42689771Scg	KASSERT(ofs < b->bufsize, ("%s: ofs invalid %d", __func__, ofs));
42774763Scg
42874763Scg	return b->buf + ofs;
42974763Scg}
43074763Scg
43174763Scgunsigned int
43274763Scgsndbuf_getsize(struct snd_dbuf *b)
43374763Scg{
43470291Scg	return b->bufsize;
43570291Scg}
43670291Scg
43774763Scgunsigned int
43874763Scgsndbuf_getmaxsize(struct snd_dbuf *b)
43970291Scg{
44074763Scg	return b->maxsize;
44174763Scg}
44274763Scg
44374763Scgunsigned int
444170722Sariffsndbuf_getallocsize(struct snd_dbuf *b)
445170722Sariff{
446170722Sariff	return b->allocsize;
447170722Sariff}
448170722Sariff
449170722Sariffunsigned int
45074763Scgsndbuf_runsz(struct snd_dbuf *b)
45174763Scg{
45270291Scg	return b->dl;
45370291Scg}
45470291Scg
45574763Scgvoid
45674763Scgsndbuf_setrun(struct snd_dbuf *b, int go)
45774763Scg{
45874763Scg	b->dl = go? b->blksz : 0;
45974763Scg}
46074763Scg
46174763Scgstruct selinfo *
46274763Scgsndbuf_getsel(struct snd_dbuf *b)
46374763Scg{
46474763Scg	return &b->sel;
46574763Scg}
46674763Scg
46774763Scg/************************************************************/
46874763Scgunsigned int
46974763Scgsndbuf_getxrun(struct snd_dbuf *b)
47074763Scg{
47174763Scg	SNDBUF_LOCKASSERT(b);
47274763Scg
47374763Scg	return b->xrun;
47474763Scg}
47574763Scg
47674763Scgvoid
477160439Snetchildsndbuf_setxrun(struct snd_dbuf *b, unsigned int xrun)
47874763Scg{
47974763Scg	SNDBUF_LOCKASSERT(b);
48074763Scg
481160439Snetchild	b->xrun = xrun;
48274763Scg}
48374763Scg
48474763Scgunsigned int
48574763Scgsndbuf_gethwptr(struct snd_dbuf *b)
48674763Scg{
48774763Scg	SNDBUF_LOCKASSERT(b);
48874763Scg
48974763Scg	return b->hp;
49074763Scg}
49174763Scg
49274763Scgvoid
49374763Scgsndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
49474763Scg{
49574763Scg	SNDBUF_LOCKASSERT(b);
49674763Scg
49774763Scg	b->hp = ptr;
49874763Scg}
49974763Scg
50074763Scgunsigned int
50174763Scgsndbuf_getready(struct snd_dbuf *b)
50274763Scg{
50374763Scg	SNDBUF_LOCKASSERT(b);
50487599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
50574763Scg
50674763Scg	return b->rl;
50774763Scg}
50874763Scg
50974763Scgunsigned int
51074763Scgsndbuf_getreadyptr(struct snd_dbuf *b)
51174763Scg{
51274763Scg	SNDBUF_LOCKASSERT(b);
51387599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
51474763Scg
51574763Scg	return b->rp;
51674763Scg}
51774763Scg
51874763Scgunsigned int
51974763Scgsndbuf_getfree(struct snd_dbuf *b)
52074763Scg{
52174763Scg	SNDBUF_LOCKASSERT(b);
52287599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
52374763Scg
52474763Scg	return b->bufsize - b->rl;
52574763Scg}
52674763Scg
52774763Scgunsigned int
52874763Scgsndbuf_getfreeptr(struct snd_dbuf *b)
52974763Scg{
53074763Scg	SNDBUF_LOCKASSERT(b);
53187599Sobrien	KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __func__, b->rp));
53287599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
53374763Scg
53474763Scg	return (b->rp + b->rl) % b->bufsize;
53574763Scg}
53674763Scg
537193640Sariffu_int64_t
53874763Scgsndbuf_getblocks(struct snd_dbuf *b)
53974763Scg{
54074763Scg	SNDBUF_LOCKASSERT(b);
54174763Scg
54274763Scg	return b->total / b->blksz;
54374763Scg}
54474763Scg
545193640Sariffu_int64_t
54674763Scgsndbuf_getprevblocks(struct snd_dbuf *b)
54774763Scg{
54874763Scg	SNDBUF_LOCKASSERT(b);
54974763Scg
55074763Scg	return b->prev_total / b->blksz;
55174763Scg}
55274763Scg
553193640Sariffu_int64_t
55474763Scgsndbuf_gettotal(struct snd_dbuf *b)
55574763Scg{
55674763Scg	SNDBUF_LOCKASSERT(b);
55774763Scg
55874763Scg	return b->total;
55974763Scg}
56074763Scg
561193640Sariffu_int64_t
562193640Sariffsndbuf_getprevtotal(struct snd_dbuf *b)
563193640Sariff{
564193640Sariff	SNDBUF_LOCKASSERT(b);
565193640Sariff
566193640Sariff	return b->prev_total;
567193640Sariff}
568193640Sariff
56974763Scgvoid
57074763Scgsndbuf_updateprevtotal(struct snd_dbuf *b)
57174763Scg{
57274763Scg	SNDBUF_LOCKASSERT(b);
57374763Scg
57474763Scg	b->prev_total = b->total;
57574763Scg}
57674763Scg
577164614Sariffunsigned int
578164614Sariffsndbuf_xbytes(unsigned int v, struct snd_dbuf *from, struct snd_dbuf *to)
579164614Sariff{
580164614Sariff	if (from == NULL || to == NULL || v == 0)
581164614Sariff		return 0;
582164614Sariff
583193640Sariff	return snd_xbytes(v, sndbuf_getalign(from) * sndbuf_getspd(from),
584193640Sariff	    sndbuf_getalign(to) * sndbuf_getspd(to));
585164614Sariff}
586164614Sariff
587164614Sariffu_int8_t
588164614Sariffsndbuf_zerodata(u_int32_t fmt)
589164614Sariff{
590193640Sariff	if (fmt & (AFMT_SIGNED | AFMT_PASSTHROUGH))
591164614Sariff		return (0x00);
592164614Sariff	else if (fmt & AFMT_MU_LAW)
593164614Sariff		return (0x7f);
594164614Sariff	else if (fmt & AFMT_A_LAW)
595164614Sariff		return (0x55);
596164614Sariff	return (0x80);
597164614Sariff}
598164614Sariff
59974763Scg/************************************************************/
60074763Scg
601162588Snetchild/**
602162588Snetchild * @brief Acquire buffer space to extend ready area
603162588Snetchild *
604162588Snetchild * This function extends the ready area length by @c count bytes, and may
605162588Snetchild * optionally copy samples from another location stored in @c from.  The
606162588Snetchild * counter @c snd_dbuf::total is also incremented by @c count bytes.
607162588Snetchild *
608162588Snetchild * @param b	audio buffer
609162588Snetchild * @param from	sample source (optional)
610162588Snetchild * @param count	number of bytes to acquire
611162588Snetchild *
612162588Snetchild * @retval 0	Unconditional
613162588Snetchild */
61470291Scgint
61574763Scgsndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
61670291Scg{
61774763Scg	int l;
61874763Scg
61987599Sobrien	KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __func__, count, sndbuf_getfree(b)));
62087599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
62174763Scg	b->total += count;
62274763Scg	if (from != NULL) {
62374763Scg		while (count > 0) {
624167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
62574763Scg			bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
62674763Scg			from += l;
62774763Scg			b->rl += l;
62874763Scg			count -= l;
62974763Scg		}
63074763Scg	} else
63174763Scg		b->rl += count;
63287599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
63374763Scg
63474763Scg	return 0;
63574763Scg}
63674763Scg
637162588Snetchild/**
638162588Snetchild * @brief Dispose samples from channel buffer, increasing size of ready area
639162588Snetchild *
640162588Snetchild * This function discards samples from the supplied buffer by advancing the
641162588Snetchild * ready area start pointer and decrementing the ready area length.  If
642162588Snetchild * @c to is not NULL, then the discard samples will be copied to the location
643162588Snetchild * it points to.
644162588Snetchild *
645162588Snetchild * @param b	PCM channel sound buffer
646162588Snetchild * @param to	destination buffer (optional)
647162588Snetchild * @param count	number of bytes to discard
648162588Snetchild *
649162588Snetchild * @returns 0 unconditionally
650162588Snetchild */
65174763Scgint
65274763Scgsndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
65374763Scg{
65474763Scg	int l;
65574763Scg
65687599Sobrien	KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __func__, count, sndbuf_getready(b)));
65787599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __func__, b->rl));
65874763Scg	if (to != NULL) {
65974763Scg		while (count > 0) {
660167641Sariff			l = min(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
66174763Scg			bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
66274763Scg			to += l;
66374763Scg			b->rl -= l;
66474763Scg			b->rp = (b->rp + l) % b->bufsize;
66574763Scg			count -= l;
66674763Scg		}
66774763Scg	} else {
66874763Scg		b->rl -= count;
66974763Scg		b->rp = (b->rp + count) % b->bufsize;
67074763Scg	}
67187599Sobrien	KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __func__, b->rl, count));
67274763Scg
67374763Scg	return 0;
67474763Scg}
67574763Scg
676193640Sariff#ifdef SND_DIAGNOSTIC
677193640Sariffstatic uint32_t snd_feeder_maxfeed = 0;
678217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxfeed, CTLFLAG_RD,
679193640Sariff    &snd_feeder_maxfeed, 0, "maximum feeder count request");
680193640Sariff
681193640Sariffstatic uint32_t snd_feeder_maxcycle = 0;
682217368SmdfSYSCTL_UINT(_hw_snd, OID_AUTO, feeder_maxcycle, CTLFLAG_RD,
683193640Sariff    &snd_feeder_maxcycle, 0, "maximum feeder cycle");
684193640Sariff#endif
685193640Sariff
68674763Scg/* count is number of bytes we want added to destination buffer */
68774763Scgint
68874763Scgsndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
68974763Scg{
690193640Sariff	unsigned int cnt, maxfeed;
691193640Sariff#ifdef SND_DIAGNOSTIC
692193640Sariff	unsigned int cycle;
693164614Sariff
694193640Sariff	if (count > snd_feeder_maxfeed)
695193640Sariff		snd_feeder_maxfeed = count;
696193640Sariff
697193640Sariff	cycle = 0;
698193640Sariff#endif
699193640Sariff
70077265Scg	KASSERT(count > 0, ("can't feed 0 bytes"));
70177265Scg
70274763Scg	if (sndbuf_getfree(to) < count)
703193640Sariff		return (EINVAL);
70474763Scg
705193640Sariff	maxfeed = SND_FXROUND(SND_FXDIV_MAX, sndbuf_getalign(to));
706193640Sariff
707164614Sariff	do {
708193640Sariff		cnt = FEEDER_FEED(feeder, channel, to->tmpbuf,
709193640Sariff		    min(count, maxfeed), from);
710193640Sariff		if (cnt == 0)
711193640Sariff			break;
712193640Sariff		sndbuf_acquire(to, to->tmpbuf, cnt);
713193640Sariff		count -= cnt;
714193640Sariff#ifdef SND_DIAGNOSTIC
715193640Sariff		cycle++;
716193640Sariff#endif
717193640Sariff	} while (count != 0);
71874763Scg
719193640Sariff#ifdef SND_DIAGNOSTIC
720193640Sariff	if (cycle > snd_feeder_maxcycle)
721193640Sariff		snd_feeder_maxcycle = cycle;
722193640Sariff#endif
723193640Sariff
724193640Sariff	return (0);
72574763Scg}
72674763Scg
72774763Scg/************************************************************/
72874763Scg
72974763Scgvoid
73074763Scgsndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
73174763Scg{
73274763Scg	printf("%s: [", s);
73374763Scg	if (what & 0x01)
73474763Scg		printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
73574763Scg	if (what & 0x02)
73674763Scg		printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
73774763Scg	if (what & 0x04)
738193640Sariff		printf(" total: %ju, prev_total: %ju, xrun: %d", (uintmax_t)b->total, (uintmax_t)b->prev_total, b->xrun);
73974763Scg   	if (what & 0x08)
74074763Scg		printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
74174763Scg	if (what & 0x10)
74274763Scg		printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
74374763Scg	printf(" ]\n");
74474763Scg}
74574763Scg
74674763Scg/************************************************************/
74774763Scgu_int32_t
74874763Scgsndbuf_getflags(struct snd_dbuf *b)
74974763Scg{
75074763Scg	return b->flags;
75174763Scg}
75274763Scg
75374763Scgvoid
75474763Scgsndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
75574763Scg{
75674763Scg	b->flags &= ~flags;
75774763Scg	if (on)
75874763Scg		b->flags |= flags;
75974763Scg}
76074763Scg
761162588Snetchild/**
762162588Snetchild * @brief Clear the shadow buffer by filling with samples equal to zero.
763162588Snetchild *
764162588Snetchild * @param b buffer to clear
765162588Snetchild */
766162588Snetchildvoid
767162588Snetchildsndbuf_clearshadow(struct snd_dbuf *b)
768162588Snetchild{
769162588Snetchild	KASSERT(b != NULL, ("b is a null pointer"));
770162588Snetchild	KASSERT(b->sl >= 0, ("illegal shadow length"));
771162588Snetchild
772164614Sariff	if ((b->shadbuf != NULL) && (b->sl > 0))
773164614Sariff		memset(b->shadbuf, sndbuf_zerodata(b->fmt), b->sl);
774162588Snetchild}
775162588Snetchild
776162588Snetchild#ifdef OSSV4_EXPERIMENT
777162588Snetchild/**
778162588Snetchild * @brief Return peak value from samples in buffer ready area.
779162588Snetchild *
780162588Snetchild * Peak ranges from 0-32767.  If channel is monaural, most significant 16
781162588Snetchild * bits will be zero.  For now, only expects to work with 1-2 channel
782162588Snetchild * buffers.
783162588Snetchild *
784162588Snetchild * @note  Currently only operates with linear PCM formats.
785162588Snetchild *
786162588Snetchild * @param b buffer to analyze
787162588Snetchild * @param lpeak pointer to store left peak value
788162588Snetchild * @param rpeak pointer to store right peak value
789162588Snetchild */
790162588Snetchildvoid
791162588Snetchildsndbuf_getpeaks(struct snd_dbuf *b, int *lp, int *rp)
792162588Snetchild{
793162588Snetchild	u_int32_t lpeak, rpeak;
794162588Snetchild
795162588Snetchild	lpeak = 0;
796162588Snetchild	rpeak = 0;
797162588Snetchild
798162588Snetchild	/**
799162588Snetchild	 * @todo fill this in later
800162588Snetchild	 */
801162588Snetchild}
802162588Snetchild#endif
803